From 70c5112a6601c64a7018fdc3e756346ed1133f90 Mon Sep 17 00:00:00 2001 From: qiin2333 <414382190@qq.com> Date: Sun, 16 Aug 2026 21:34:16 +0800 Subject: [PATCH 1/4] fix(hdr): select display modes within HDR candidates --- .../java/com/limelight/DisplayModeManager.kt | 116 ++++++------------ .../java/com/limelight/DisplayModePolicy.kt | 115 +++++++++++++++++ .../com/limelight/DisplayModePolicyTest.kt | 97 +++++++++++++++ 3 files changed, 251 insertions(+), 77 deletions(-) create mode 100644 app/src/main/java/com/limelight/DisplayModePolicy.kt create mode 100644 app/src/test/java/com/limelight/DisplayModePolicyTest.kt diff --git a/app/src/main/java/com/limelight/DisplayModeManager.kt b/app/src/main/java/com/limelight/DisplayModeManager.kt index 0274441dc7..19c0281187 100644 --- a/app/src/main/java/com/limelight/DisplayModeManager.kt +++ b/app/src/main/java/com/limelight/DisplayModeManager.kt @@ -5,7 +5,6 @@ import android.view.Display import com.limelight.preferences.PreferenceConfiguration import com.limelight.utils.UiHelper import kotlin.math.abs -import kotlin.math.roundToInt /** * 显示模式管理器 @@ -25,11 +24,11 @@ object DisplayModeManager { ) fun isRefreshRateEqualMatch(refreshRate: Float, targetFps: Int): Boolean { - return refreshRate >= targetFps && refreshRate <= targetFps + 3 + return DisplayModePolicy.isRefreshRateEqualMatch(refreshRate, targetFps) } fun isRefreshRateGoodMatch(refreshRate: Float, targetFps: Int): Boolean { - return refreshRate >= targetFps && refreshRate.roundToInt() % targetFps <= 3 + return DisplayModePolicy.isRefreshRateGoodMatch(refreshRate, targetFps) } fun mayReduceRefreshRate(prefConfig: PreferenceConfiguration): Boolean { @@ -74,84 +73,32 @@ object DisplayModeManager { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { val supportedModes = display.supportedModes - val eligibleModes = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE && - acceptableHdrTypes.isNotEmpty() - ) { - supportedModes.filter { mode -> - mode.supportedHdrTypes.any { supportedType -> - acceptableHdrTypes.any { it == supportedType } - } - }.ifEmpty { - LimeLog.warning("No display mode supports the requested HDR type; using normal mode selection") - supportedModes.asList() - } + val isNativeResolutionStream = prefConfig.usesNativeDisplayMode + val effectiveHdrTypes = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + acceptableHdrTypes } else { - supportedModes.asList() + IntArray(0) } - - // Start from the mode Android is actually using. A candidate may be - // rejected by the resolution/refresh-rate constraints below; in that - // case we must keep the current mode instead of retaining an arbitrary - // first HDR-eligible mode that was never validated by those constraints. - var bestMode = display.mode - val isNativeResolutionStream = prefConfig.usesNativeDisplayMode - var refreshRateIsGood = isRefreshRateGoodMatch(bestMode.refreshRate, prefConfig.fps) - var refreshRateIsEqual = isRefreshRateEqualMatch(bestMode.refreshRate, prefConfig.fps) - - LimeLog.info("Current display mode: ${bestMode.physicalWidth}x${bestMode.physicalHeight}x${bestMode.refreshRate}") - - for (candidate in eligibleModes) { - val refreshRateReduced = candidate.refreshRate < bestMode.refreshRate - val resolutionReduced = candidate.physicalWidth < bestMode.physicalWidth || - candidate.physicalHeight < bestMode.physicalHeight - val resolutionFitsStream = candidate.physicalWidth >= prefConfig.width && - candidate.physicalHeight >= prefConfig.height - - LimeLog.info("Examining display mode: ${candidate.physicalWidth}x${candidate.physicalHeight}x${candidate.refreshRate}") - - if (candidate.physicalWidth > 4096 && prefConfig.width <= 4096) { - continue - } - - if (prefConfig.width < 3840 && prefConfig.fps <= 60 && !isNativeResolutionStream) { - if (display.mode.physicalWidth != candidate.physicalWidth || - display.mode.physicalHeight != candidate.physicalHeight - ) { - continue - } - } - - if (resolutionReduced && !(prefConfig.fps > 60 && resolutionFitsStream)) { - continue - } - - if (mayReduceRefreshRate(prefConfig) && refreshRateIsEqual && !isRefreshRateEqualMatch(candidate.refreshRate, prefConfig.fps)) { - continue - } else if (refreshRateIsGood) { - if (!isRefreshRateGoodMatch(candidate.refreshRate, prefConfig.fps)) { - continue - } - - if (mayReduceRefreshRate(prefConfig)) { - if (candidate.refreshRate > bestMode.refreshRate) { - continue - } - } else { - if (refreshRateReduced) { - continue - } - } - } else if (!isRefreshRateGoodMatch(candidate.refreshRate, prefConfig.fps)) { - if (refreshRateReduced) { - continue - } - } - - bestMode = candidate - refreshRateIsGood = isRefreshRateGoodMatch(candidate.refreshRate, prefConfig.fps) - refreshRateIsEqual = isRefreshRateEqualMatch(candidate.refreshRate, prefConfig.fps) + val currentMode = display.mode.toPolicyMode() + val policyResult = DisplayModePolicy.selectBestMode( + currentMode = currentMode, + supportedModes = supportedModes.map { it.toPolicyMode() }, + request = DisplayModePolicy.Request( + width = prefConfig.width, + height = prefConfig.height, + fps = prefConfig.fps, + usesNativeDisplayMode = isNativeResolutionStream, + mayReduceRefreshRate = mayReduceRefreshRate(prefConfig), + acceptableHdrTypes = effectiveHdrTypes, + ), + ) + if (effectiveHdrTypes.isNotEmpty() && !policyResult.hdrFilterApplied) { + LimeLog.warning("No display mode supports the requested HDR type; using normal mode selection") } + val bestMode = supportedModes.firstOrNull { it.modeId == policyResult.mode.id } ?: display.mode + LimeLog.info("Current display mode: ${display.mode.physicalWidth}x${display.mode.physicalHeight}x${display.mode.refreshRate}") + LimeLog.info("Best display mode: ${bestMode.physicalWidth}x${bestMode.physicalHeight}x${bestMode.refreshRate}") if (display.mode.modeId != bestMode.modeId) { @@ -220,4 +167,19 @@ object DisplayModeManager { aspectRatioMatch = aspectRatioMatch ) } + + @Suppress("NewApi") + private fun Display.Mode.toPolicyMode(): DisplayModePolicy.Mode { + return DisplayModePolicy.Mode( + id = modeId, + width = physicalWidth, + height = physicalHeight, + refreshRate = refreshRate, + hdrTypes = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + supportedHdrTypes + } else { + IntArray(0) + }, + ) + } } diff --git a/app/src/main/java/com/limelight/DisplayModePolicy.kt b/app/src/main/java/com/limelight/DisplayModePolicy.kt new file mode 100644 index 0000000000..fb11804b41 --- /dev/null +++ b/app/src/main/java/com/limelight/DisplayModePolicy.kt @@ -0,0 +1,115 @@ +package com.limelight + +import kotlin.math.roundToInt + +/** Pure display-mode selection policy, independent of Android framework objects. */ +internal object DisplayModePolicy { + data class Mode( + val id: Int, + val width: Int, + val height: Int, + val refreshRate: Float, + val hdrTypes: IntArray = IntArray(0), + ) + + data class Request( + val width: Int, + val height: Int, + val fps: Int, + val usesNativeDisplayMode: Boolean, + val mayReduceRefreshRate: Boolean, + val acceptableHdrTypes: IntArray = IntArray(0), + ) + + data class Result( + val mode: Mode, + val hdrFilterApplied: Boolean, + ) + + fun selectBestMode( + currentMode: Mode, + supportedModes: List, + request: Request, + ): Result { + val hdrModes = if (request.acceptableHdrTypes.isNotEmpty()) { + supportedModes.filter { it.supportsAny(request.acceptableHdrTypes) } + } else { + emptyList() + } + val hdrFilterApplied = hdrModes.isNotEmpty() + val eligibleModes = if (hdrFilterApplied) hdrModes else supportedModes + + // An HDR request must be optimized entirely within the matching HDR set. Keep the + // current mode as the baseline only when it belongs to that set; otherwise the first + // candidate that passes the resolution constraints establishes the HDR baseline. + var bestMode: Mode? = currentMode.takeIf { !hdrFilterApplied || it.supportsAny(request.acceptableHdrTypes) } + var refreshRateIsGood = bestMode?.let { isRefreshRateGoodMatch(it.refreshRate, request.fps) } ?: false + var refreshRateIsEqual = bestMode?.let { isRefreshRateEqualMatch(it.refreshRate, request.fps) } ?: false + + for (candidate in eligibleModes) { + val comparisonMode = bestMode ?: currentMode + val resolutionReduced = candidate.width < comparisonMode.width || + candidate.height < comparisonMode.height + val resolutionFitsStream = candidate.width >= request.width && + candidate.height >= request.height + + if (candidate.width > 4096 && request.width <= 4096) { + continue + } + + if (request.width < 3840 && request.fps <= 60 && !request.usesNativeDisplayMode && + (currentMode.width != candidate.width || currentMode.height != candidate.height) + ) { + continue + } + + if (resolutionReduced && !(request.fps > 60 && resolutionFitsStream)) { + continue + } + + // There is no valid HDR baseline yet. The first resolution-compatible HDR mode + // must not be compared against an SDR mode's refresh rate. + if (bestMode != null) { + val refreshRateReduced = candidate.refreshRate < bestMode.refreshRate + + if (request.mayReduceRefreshRate && refreshRateIsEqual && + !isRefreshRateEqualMatch(candidate.refreshRate, request.fps) + ) { + continue + } else if (refreshRateIsGood) { + if (!isRefreshRateGoodMatch(candidate.refreshRate, request.fps)) { + continue + } + + if (request.mayReduceRefreshRate) { + if (candidate.refreshRate > bestMode.refreshRate) { + continue + } + } else if (refreshRateReduced) { + continue + } + } else if (!isRefreshRateGoodMatch(candidate.refreshRate, request.fps) && refreshRateReduced) { + continue + } + } + + bestMode = candidate + refreshRateIsGood = isRefreshRateGoodMatch(candidate.refreshRate, request.fps) + refreshRateIsEqual = isRefreshRateEqualMatch(candidate.refreshRate, request.fps) + } + + return Result(bestMode ?: currentMode, hdrFilterApplied) + } + + fun isRefreshRateEqualMatch(refreshRate: Float, targetFps: Int): Boolean { + return refreshRate >= targetFps && refreshRate <= targetFps + 3 + } + + fun isRefreshRateGoodMatch(refreshRate: Float, targetFps: Int): Boolean { + return refreshRate >= targetFps && refreshRate.roundToInt() % targetFps <= 3 + } + + private fun Mode.supportsAny(acceptableHdrTypes: IntArray): Boolean { + return hdrTypes.any { supportedType -> acceptableHdrTypes.any { it == supportedType } } + } +} \ No newline at end of file diff --git a/app/src/test/java/com/limelight/DisplayModePolicyTest.kt b/app/src/test/java/com/limelight/DisplayModePolicyTest.kt new file mode 100644 index 0000000000..592ca770ea --- /dev/null +++ b/app/src/test/java/com/limelight/DisplayModePolicyTest.kt @@ -0,0 +1,97 @@ +package com.limelight + +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Test + +class DisplayModePolicyTest { + @Test + fun selectsLowerRefreshHdrModeWhenCurrentModeDoesNotSupportHdr() { + val currentSdrMode = mode(id = 1, refreshRate = 120f) + val hdrMode = mode(id = 2, refreshRate = 60f, hdrTypes = intArrayOf(HDR10)) + + val result = DisplayModePolicy.selectBestMode( + currentMode = currentSdrMode, + supportedModes = listOf(currentSdrMode, hdrMode), + request = request(acceptableHdrTypes = intArrayOf(HDR10)), + ) + + assertEquals(hdrMode, result.mode) + assertTrue(result.hdrFilterApplied) + } + + @Test + fun keepsCurrentModeWhenItSupportsRequestedHdrType() { + val currentHdrMode = mode(id = 1, refreshRate = 120f, hdrTypes = intArrayOf(HDR10)) + val lowerRefreshHdrMode = mode(id = 2, refreshRate = 60f, hdrTypes = intArrayOf(HDR10)) + + val result = DisplayModePolicy.selectBestMode( + currentMode = currentHdrMode, + supportedModes = listOf(currentHdrMode, lowerRefreshHdrMode), + request = request(acceptableHdrTypes = intArrayOf(HDR10)), + ) + + assertEquals(currentHdrMode, result.mode) + assertTrue(result.hdrFilterApplied) + } + + @Test + fun fallsBackToNormalSelectionWhenNoModeSupportsRequestedHdrType() { + val currentSdrMode = mode(id = 1, refreshRate = 60f) + val fasterSdrMode = mode(id = 2, refreshRate = 120f) + + val result = DisplayModePolicy.selectBestMode( + currentMode = currentSdrMode, + supportedModes = listOf(currentSdrMode, fasterSdrMode), + request = request(acceptableHdrTypes = intArrayOf(HDR10)), + ) + + assertEquals(fasterSdrMode, result.mode) + assertFalse(result.hdrFilterApplied) + } + + @Test + fun doesNotRetainHdrCandidateThatViolatesResolutionConstraints() { + val currentSdrMode = mode(id = 1, width = 3840, height = 2160, refreshRate = 120f) + val undersizedHdrMode = mode( + id = 2, + width = 1920, + height = 1080, + refreshRate = 60f, + hdrTypes = intArrayOf(HDR10), + ) + + val result = DisplayModePolicy.selectBestMode( + currentMode = currentSdrMode, + supportedModes = listOf(currentSdrMode, undersizedHdrMode), + request = request(acceptableHdrTypes = intArrayOf(HDR10)), + ) + + assertEquals(currentSdrMode, result.mode) + assertTrue(result.hdrFilterApplied) + } + + private fun mode( + id: Int, + width: Int = 3840, + height: Int = 2160, + refreshRate: Float, + hdrTypes: IntArray = IntArray(0), + ) = DisplayModePolicy.Mode(id, width, height, refreshRate, hdrTypes) + + private fun request( + acceptableHdrTypes: IntArray, + ) = DisplayModePolicy.Request( + width = 3840, + height = 2160, + fps = 60, + usesNativeDisplayMode = true, + mayReduceRefreshRate = false, + acceptableHdrTypes = acceptableHdrTypes, + ) + + private companion object { + const val HDR10 = 2 + } +} \ No newline at end of file From 26a7f7c89d870d220ce2bbc72cc9019868ca0b22 Mon Sep 17 00:00:00 2001 From: qiin2333 <414382190@qq.com> Date: Sun, 16 Aug 2026 21:37:09 +0800 Subject: [PATCH 2/4] chore: pin common-c to latest mic --- app/src/main/jni/moonlight-core/moonlight-common-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/jni/moonlight-core/moonlight-common-c b/app/src/main/jni/moonlight-core/moonlight-common-c index f894aabf2d..72733e3a47 160000 --- a/app/src/main/jni/moonlight-core/moonlight-common-c +++ b/app/src/main/jni/moonlight-core/moonlight-common-c @@ -1 +1 @@ -Subproject commit f894aabf2d4c33e3c437e01ffca758260aa04f0e +Subproject commit 72733e3a47fc7823e7e0b1b0cef2e3d101b0399b From c14625202c8194cca7d574ee53cdddce12be550e Mon Sep 17 00:00:00 2001 From: qiin2333 <414382190@qq.com> Date: Sun, 16 Aug 2026 21:40:16 +0800 Subject: [PATCH 3/4] fix(build): include common-c DS5 haptics sources --- app/src/main/jni/moonlight-core/Android.mk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/jni/moonlight-core/Android.mk b/app/src/main/jni/moonlight-core/Android.mk index e2d6c1f328..b8f463bbda 100644 --- a/app/src/main/jni/moonlight-core/Android.mk +++ b/app/src/main/jni/moonlight-core/Android.mk @@ -18,6 +18,8 @@ LOCAL_SRC_FILES := moonlight-common-c/src/AudioStream.c \ moonlight-common-c/src/ConnectionTester.c \ moonlight-common-c/src/ControlStream.c \ moonlight-common-c/src/CursorStream.c \ + moonlight-common-c/src/Ds5HapticsIrStream.c \ + moonlight-common-c/src/Ds5HapticsStream.c \ moonlight-common-c/src/FakeCallbacks.c \ moonlight-common-c/src/InputStream.c \ moonlight-common-c/src/LinkedBlockingQueue.c \ From 2dc55b28f576f9da4b2d0d40f9f7b0545674f322 Mon Sep 17 00:00:00 2001 From: qiin2333 <414382190@qq.com> Date: Sun, 16 Aug 2026 21:55:41 +0800 Subject: [PATCH 4/4] fix(hdr): address display mode review feedback --- .../java/com/limelight/DisplayModeManager.kt | 15 ++++++---- .../java/com/limelight/DisplayModePolicy.kt | 8 +++--- .../com/limelight/DisplayModePolicyTest.kt | 28 ++++++++++++------- 3 files changed, 32 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/com/limelight/DisplayModeManager.kt b/app/src/main/java/com/limelight/DisplayModeManager.kt index 19c0281187..5514224efe 100644 --- a/app/src/main/java/com/limelight/DisplayModeManager.kt +++ b/app/src/main/java/com/limelight/DisplayModeManager.kt @@ -2,6 +2,7 @@ package com.limelight import android.os.Build import android.view.Display +import androidx.annotation.RequiresApi import com.limelight.preferences.PreferenceConfiguration import com.limelight.utils.UiHelper import kotlin.math.abs @@ -75,9 +76,9 @@ object DisplayModeManager { val supportedModes = display.supportedModes val isNativeResolutionStream = prefConfig.usesNativeDisplayMode val effectiveHdrTypes = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { - acceptableHdrTypes + acceptableHdrTypes.toList() } else { - IntArray(0) + emptyList() } val currentMode = display.mode.toPolicyMode() val policyResult = DisplayModePolicy.selectBestMode( @@ -94,6 +95,10 @@ object DisplayModeManager { ) if (effectiveHdrTypes.isNotEmpty() && !policyResult.hdrFilterApplied) { LimeLog.warning("No display mode supports the requested HDR type; using normal mode selection") + } else if (effectiveHdrTypes.isNotEmpty() && + policyResult.mode.hdrTypes.none(effectiveHdrTypes::contains) + ) { + LimeLog.warning("HDR-capable modes exist but none met the display mode constraints") } val bestMode = supportedModes.firstOrNull { it.modeId == policyResult.mode.id } ?: display.mode @@ -168,7 +173,7 @@ object DisplayModeManager { ) } - @Suppress("NewApi") + @RequiresApi(Build.VERSION_CODES.M) private fun Display.Mode.toPolicyMode(): DisplayModePolicy.Mode { return DisplayModePolicy.Mode( id = modeId, @@ -176,9 +181,9 @@ object DisplayModeManager { height = physicalHeight, refreshRate = refreshRate, hdrTypes = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { - supportedHdrTypes + supportedHdrTypes.toList() } else { - IntArray(0) + emptyList() }, ) } diff --git a/app/src/main/java/com/limelight/DisplayModePolicy.kt b/app/src/main/java/com/limelight/DisplayModePolicy.kt index fb11804b41..de477781f0 100644 --- a/app/src/main/java/com/limelight/DisplayModePolicy.kt +++ b/app/src/main/java/com/limelight/DisplayModePolicy.kt @@ -9,7 +9,7 @@ internal object DisplayModePolicy { val width: Int, val height: Int, val refreshRate: Float, - val hdrTypes: IntArray = IntArray(0), + val hdrTypes: List = emptyList(), ) data class Request( @@ -18,7 +18,7 @@ internal object DisplayModePolicy { val fps: Int, val usesNativeDisplayMode: Boolean, val mayReduceRefreshRate: Boolean, - val acceptableHdrTypes: IntArray = IntArray(0), + val acceptableHdrTypes: List = emptyList(), ) data class Result( @@ -109,7 +109,7 @@ internal object DisplayModePolicy { return refreshRate >= targetFps && refreshRate.roundToInt() % targetFps <= 3 } - private fun Mode.supportsAny(acceptableHdrTypes: IntArray): Boolean { - return hdrTypes.any { supportedType -> acceptableHdrTypes.any { it == supportedType } } + private fun Mode.supportsAny(acceptableHdrTypes: List): Boolean { + return hdrTypes.any(acceptableHdrTypes::contains) } } \ No newline at end of file diff --git a/app/src/test/java/com/limelight/DisplayModePolicyTest.kt b/app/src/test/java/com/limelight/DisplayModePolicyTest.kt index 592ca770ea..acb8171f92 100644 --- a/app/src/test/java/com/limelight/DisplayModePolicyTest.kt +++ b/app/src/test/java/com/limelight/DisplayModePolicyTest.kt @@ -9,12 +9,12 @@ class DisplayModePolicyTest { @Test fun selectsLowerRefreshHdrModeWhenCurrentModeDoesNotSupportHdr() { val currentSdrMode = mode(id = 1, refreshRate = 120f) - val hdrMode = mode(id = 2, refreshRate = 60f, hdrTypes = intArrayOf(HDR10)) + val hdrMode = mode(id = 2, refreshRate = 60f, hdrTypes = listOf(HDR10)) val result = DisplayModePolicy.selectBestMode( currentMode = currentSdrMode, supportedModes = listOf(currentSdrMode, hdrMode), - request = request(acceptableHdrTypes = intArrayOf(HDR10)), + request = request(acceptableHdrTypes = listOf(HDR10)), ) assertEquals(hdrMode, result.mode) @@ -23,13 +23,13 @@ class DisplayModePolicyTest { @Test fun keepsCurrentModeWhenItSupportsRequestedHdrType() { - val currentHdrMode = mode(id = 1, refreshRate = 120f, hdrTypes = intArrayOf(HDR10)) - val lowerRefreshHdrMode = mode(id = 2, refreshRate = 60f, hdrTypes = intArrayOf(HDR10)) + val currentHdrMode = mode(id = 1, refreshRate = 120f, hdrTypes = listOf(HDR10)) + val lowerRefreshHdrMode = mode(id = 2, refreshRate = 60f, hdrTypes = listOf(HDR10)) val result = DisplayModePolicy.selectBestMode( currentMode = currentHdrMode, supportedModes = listOf(currentHdrMode, lowerRefreshHdrMode), - request = request(acceptableHdrTypes = intArrayOf(HDR10)), + request = request(acceptableHdrTypes = listOf(HDR10)), ) assertEquals(currentHdrMode, result.mode) @@ -44,7 +44,7 @@ class DisplayModePolicyTest { val result = DisplayModePolicy.selectBestMode( currentMode = currentSdrMode, supportedModes = listOf(currentSdrMode, fasterSdrMode), - request = request(acceptableHdrTypes = intArrayOf(HDR10)), + request = request(acceptableHdrTypes = listOf(HDR10)), ) assertEquals(fasterSdrMode, result.mode) @@ -59,29 +59,37 @@ class DisplayModePolicyTest { width = 1920, height = 1080, refreshRate = 60f, - hdrTypes = intArrayOf(HDR10), + hdrTypes = listOf(HDR10), ) val result = DisplayModePolicy.selectBestMode( currentMode = currentSdrMode, supportedModes = listOf(currentSdrMode, undersizedHdrMode), - request = request(acceptableHdrTypes = intArrayOf(HDR10)), + request = request(acceptableHdrTypes = listOf(HDR10)), ) assertEquals(currentSdrMode, result.mode) assertTrue(result.hdrFilterApplied) } + @Test + fun modeEqualityUsesHdrTypeValues() { + assertEquals( + mode(id = 1, refreshRate = 60f, hdrTypes = listOf(HDR10)), + mode(id = 1, refreshRate = 60f, hdrTypes = listOf(HDR10)), + ) + } + private fun mode( id: Int, width: Int = 3840, height: Int = 2160, refreshRate: Float, - hdrTypes: IntArray = IntArray(0), + hdrTypes: List = emptyList(), ) = DisplayModePolicy.Mode(id, width, height, refreshRate, hdrTypes) private fun request( - acceptableHdrTypes: IntArray, + acceptableHdrTypes: List, ) = DisplayModePolicy.Request( width = 3840, height = 2160,