From 72dac2bd36c3476498fb13cf8d6b3739a1efbe91 Mon Sep 17 00:00:00 2001 From: TioaChan <8370450+TioaChan@users.noreply.github.com> Date: Fri, 23 Oct 2026 13:32:59 +0800 Subject: [PATCH] fix: preserve CarPlay physical size across browser viewport changes A smaller browser canvas was reported as a fraction of the largest viewport ever observed. With Medium and a saved 3840-pixel maximum, 1184x920 was announced as 93x72 mm, making iOS controls oversized. Use the current canvas as the physical reference so the selected length remains stable across browser resizing and pixel-resolution changes. Keep the shared resolver's existing width/height reference handling. Add host regressions for the reported dimensions, repeated resizing, all size presets, and a saved height reference. All four fail against the original code and pass with the fix. --- .../shilapi/xcertplay/CarPlayHostActivity.kt | 6 +- .../CarPlayBrowserDisplaySizeTest.kt | 56 +++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 common/src/test/java/com/shilapi/xcertplay/CarPlayBrowserDisplaySizeTest.kt diff --git a/common/src/main/java/com/shilapi/xcertplay/CarPlayHostActivity.kt b/common/src/main/java/com/shilapi/xcertplay/CarPlayHostActivity.kt index 5e1ef7d..9b400f1 100644 --- a/common/src/main/java/com/shilapi/xcertplay/CarPlayHostActivity.kt +++ b/common/src/main/java/com/shilapi/xcertplay/CarPlayHostActivity.kt @@ -2689,8 +2689,10 @@ class CarPlayHostActivity : ComponentActivity() { AirPlayDisplaySettings.resolvePhysicalSizeMm( currentWidthPixels = size.width, currentHeightPixels = size.height, - maximumWidthPixels = maxOf(maximumDetectedWidthPixels, size.width), - maximumHeightPixels = maxOf(maximumDetectedHeightPixels, size.height), + // The browser canvas fills its display at every pixel resolution. Treating it as + // a fraction of a previous viewport shrinks the reported screen and enlarges iOS UI. + maximumWidthPixels = size.width, + maximumHeightPixels = size.height, referenceMillimeters = widthPhysicalMm, basis = physicalSizeBasis, ) diff --git a/common/src/test/java/com/shilapi/xcertplay/CarPlayBrowserDisplaySizeTest.kt b/common/src/test/java/com/shilapi/xcertplay/CarPlayBrowserDisplaySizeTest.kt new file mode 100644 index 0000000..836e95a --- /dev/null +++ b/common/src/test/java/com/shilapi/xcertplay/CarPlayBrowserDisplaySizeTest.kt @@ -0,0 +1,56 @@ +package com.shilapi.xcertplay + +import com.shilapi.xcertplay.airplay.AirPlayPhysicalSizeBasis +import com.shilapi.xcertplay.airplay.AirPlayPhysicalSizeMm +import com.shilapi.xcertplay.airplay.CarPlaySize +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.Robolectric +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import org.robolectric.util.ReflectionHelpers + +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [29]) +class CarPlayBrowserDisplaySizeTest { + private fun host(): CarPlayHostActivity = + Robolectric.buildActivity(CarPlayHostActivity::class.java).get().also { + ReflectionHelpers.setField(it, "maximumDetectedWidthPixels", 3840) + ReflectionHelpers.setField(it, "maximumDetectedHeightPixels", 2160) + ReflectionHelpers.setField(it, "widthPhysicalMm", CarPlaySize.MEDIUM.widthMillimeters) + } + + private fun physicalSize(host: CarPlayHostActivity, width: Int, height: Int): AirPlayPhysicalSizeMm { + val sizeClass = CarPlayHostActivity::class.java.declaredClasses.single { it.simpleName == "DisplaySize" } + val size = sizeClass.getDeclaredConstructor(Int::class.javaPrimitiveType, Int::class.javaPrimitiveType) + .apply { isAccessible = true }.newInstance(width, height) + return CarPlayHostActivity::class.java.getDeclaredMethod("resolvePhysicalSize", sizeClass) + .apply { isAccessible = true }.invoke(host, size) as AirPlayPhysicalSizeMm + } + + @Test fun mediumBrowserCanvasKeepsItsPhysicalSizeAfterAFourKViewport() { + assertEquals(AirPlayPhysicalSizeMm(300, 233), physicalSize(host(), 1184, 920)) + } + + @Test fun resizingTheBrowserOrReducingPixelsDoesNotEnlargeCarPlayControls() { + val host = host() + assertEquals(AirPlayPhysicalSizeMm(300, 169), physicalSize(host, 1920, 1080)) + assertEquals(AirPlayPhysicalSizeMm(300, 233), physicalSize(host, 1184, 920)) + assertEquals(AirPlayPhysicalSizeMm(300, 233), physicalSize(host, 592, 460)) + } + + @Test fun eachCarPlaySizePresetKeepsItsConfiguredWidth() { + val host = host() + for (preset in CarPlaySize.entries) { + ReflectionHelpers.setField(host, "widthPhysicalMm", preset.widthMillimeters) + assertEquals(preset.widthMillimeters, physicalSize(host, 1184, 920).widthMm) + } + } + + @Test fun aSavedHeightReferenceAlsoKeepsItsConfiguredLength() { + val host = host() + ReflectionHelpers.setField(host, "physicalSizeBasis", AirPlayPhysicalSizeBasis.HEIGHT) + assertEquals(AirPlayPhysicalSizeMm(386, 300), physicalSize(host, 1184, 920)) + } +}