From 5d220543eb273258db69e37cbfd0b9c3b60f17f7 Mon Sep 17 00:00:00 2001 From: Masashi Katsumata Date: Fri, 6 Nov 2026 19:25:12 -0800 Subject: [PATCH] Keep the whole map design across configuration changes MapplsMapViewSaver saved only styleName, so the id came back as "default" and attribution rules were lost. Adds a device round-trip test. --- build.gradle.kts | 5 ++ .../mappls/MapplsMapViewSaverTest.kt | 79 +++++++++++++++++++ .../mappls/MapplsViewStateImpl.kt | 7 +- 3 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 src/androidTest/java/com/mapconductor/mappls/MapplsMapViewSaverTest.kt diff --git a/build.gradle.kts b/build.gradle.kts index 92281d1..8b66e67 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -29,6 +29,7 @@ android { defaultConfig { minSdk = project.property("minSdk").toString().toInt() + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles("consumer-rules.pro") } @@ -82,6 +83,10 @@ dependencies { } testImplementation(libs.junit) + + // Saver の保存 → 復元を実機の Bundle / Parcel で確かめる(SaverRoundTripTest)。 + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) } // Set project version for NMCP plugin diff --git a/src/androidTest/java/com/mapconductor/mappls/MapplsMapViewSaverTest.kt b/src/androidTest/java/com/mapconductor/mappls/MapplsMapViewSaverTest.kt new file mode 100644 index 0000000..05b1bf4 --- /dev/null +++ b/src/androidTest/java/com/mapconductor/mappls/MapplsMapViewSaverTest.kt @@ -0,0 +1,79 @@ +package com.mapconductor.mappls + +import androidx.compose.runtime.saveable.Saver +import androidx.compose.runtime.saveable.SaverScope +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.mapconductor.core.features.GeoPoint +import com.mapconductor.core.map.AttributionRule +import com.mapconductor.core.map.MapCameraPosition +import com.mapconductor.core.map.MapUISettings +import org.junit.Assert.assertEquals +import org.junit.Assert.assertSame +import org.junit.Assert.assertTrue +import org.junit.Test +import org.junit.runner.RunWith +import android.os.Bundle +import android.os.Parcel + +/** + * 回転などの構成変更で state が [MapplsMapViewSaver] を通って作り直されても、デザイン(id・ + * attributionRules ほか)と uiSettings・カメラが落ちないこと。Bundle は実機の Parcel を一度通す。 + */ +@RunWith(AndroidJUnit4::class) +class MapplsMapViewSaverTest { + private val rules = + listOf(AttributionRule("© test"), AttributionRule("© ranged", minZoom = 3, maxZoom = 15)) + + private val camera = + MapCameraPosition( + position = GeoPoint(21.38, -157.93), + zoom = 12.0, + bearing = 20.0, + tilt = 10.0, + ) + + @Test + fun keepsDesignWithAttributionRules() { + val design = MapplsDesign(id = "contract-style", styleName = "contract_style_name", attributionRules = rules) + val state = MapplsViewState(mapDesignType = design, id = "mappls-1", cameraPosition = camera) + state.uiSettings = MapUISettings(rotateGesture = false, tiltGesture = false) + + val restored = roundTrip(MapplsMapViewSaver().createSaver(), state) + + // 以前は styleName しか保存しておらず、id は default に戻っていた。 + assertEquals(design, restored.mapDesignType) + assertCommon(restored, "mappls-1") + } + + @Test + fun keepsPresetDesign() { + val state = MapplsViewState(mapDesignType = MapplsDesign.StandardDay, id = "mappls-2") + assertEquals(MapplsDesign.StandardDay, roundTrip(MapplsMapViewSaver().createSaver(), state).mapDesignType) + } + + private fun assertCommon(restored: com.mapconductor.core.map.MapViewStateInterface<*>, id: String) { + assertEquals(id, restored.id) + assertEquals(false, restored.uiSettings.rotateGesture) + assertEquals(false, restored.uiSettings.tiltGesture) + assertEquals(true, restored.uiSettings.scrollGesture) + assertEquals(12.0, restored.cameraPosition.zoom, 1e-9) + assertEquals(20.0, restored.cameraPosition.bearing, 1e-9) + assertEquals(21.38, restored.cameraPosition.position.latitude, 1e-9) + } + + private fun roundTrip( + saver: Saver, + value: T, + ): T { + val saved = with(saver) { SaverScope { true }.save(value) }!! + // 一度 Parcel に書いて読み戻す(プロセスが落ちたあとの復元と同じ経路)。 + val parcel = Parcel.obtain() + try { + parcel.writeBundle(saved) + parcel.setDataPosition(0) + return saver.restore(parcel.readBundle(javaClass.classLoader)!!)!! + } finally { + parcel.recycle() + } + } +} diff --git a/src/main/java/com/mapconductor/mappls/MapplsViewStateImpl.kt b/src/main/java/com/mapconductor/mappls/MapplsViewStateImpl.kt index 50dac25..6e73d5b 100644 --- a/src/main/java/com/mapconductor/mappls/MapplsViewStateImpl.kt +++ b/src/main/java/com/mapconductor/mappls/MapplsViewStateImpl.kt @@ -8,6 +8,7 @@ import com.mapconductor.compose.map.BaseMapViewSaver import com.mapconductor.core.map.MapCameraPosition import com.mapconductor.core.map.MapCameraPositionInterface import com.mapconductor.core.map.MapViewState +import com.mapconductor.core.map.MapViewStateBundle import com.mapconductor.core.map.MapViewStateInterface import java.util.UUID import android.os.Bundle @@ -53,7 +54,10 @@ class MapplsMapViewSaver : BaseMapViewSaver() { state: MapplsViewState, bundle: Bundle, ) { - bundle.putString("styleName", state.mapDesignType.styleName) + val design = state.mapDesignType + bundle.putString("id", design.id) + bundle.putString("styleName", design.styleName) + MapViewStateBundle.putAttributionRules(bundle, design.attributionRules) } override fun createState( @@ -71,6 +75,7 @@ class MapplsMapViewSaver : BaseMapViewSaver() { styleName = mapDesignBundle?.getString("styleName") ?: MapplsDesign.Default.styleName, + attributionRules = MapViewStateBundle.getAttributionRules(mapDesignBundle), ), cameraPosition = cameraPosition, )