diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1f519bb3..a035b424 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,6 +30,7 @@ materialIconsExtendedAndroid = "1.7.8" # Google Maps Platform mapsecrets = "2.0.1" mapsktx = "6.4.1" +mapsRobolectric = "1.0.0" # Testing androidCore = "1.7.0" @@ -74,6 +75,7 @@ material = { group = "com.google.android.material", name = "material", version.r maps-ktx-std = { module = "com.google.maps.android:maps-ktx", version.ref = "mapsktx" } maps-ktx-utils = { module = "com.google.maps.android:maps-utils-ktx", version.ref = "mapsktx" } maps-secrets-plugin = { module = "com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin", version.ref = "mapsecrets" } +maps-robolectric-shadows = { module = "com.google.android.maps.robolectric:shadows", version.ref = "mapsRobolectric" } # Testing androidx-test-compose-ui = { module = "androidx.compose.ui:ui-test-junit4" } diff --git a/maps-compose/build.gradle.kts b/maps-compose/build.gradle.kts index 329f934b..a19f5cd1 100644 --- a/maps-compose/build.gradle.kts +++ b/maps-compose/build.gradle.kts @@ -57,6 +57,12 @@ android { enableAndroidTestCoverage = true } } + + testOptions { + unitTests { + isIncludeAndroidResources = true + } + } } kotlin { @@ -93,6 +99,14 @@ dependencies { api(libs.maps.ktx.std) testImplementation(libs.test.junit) + testImplementation(libs.robolectric) + testImplementation(libs.truth) + testImplementation(libs.kotlinx.coroutines.test) + testImplementation(libs.maps.robolectric.shadows) + testImplementation(libs.mockk) + testImplementation(libs.androidx.test.compose.ui) + testImplementation(libs.androidx.activity.compose) + testImplementation(libs.androidx.test.core) androidTestImplementation(platform(libs.androidx.compose.bom)) androidTestImplementation(libs.androidx.test.espresso) @@ -132,4 +146,10 @@ dokka { dokkaSourceSets.configureEach { } +} + +tasks.withType().configureEach { + javaLauncher.set(javaToolchains.launcherFor { + languageVersion.set(JavaLanguageVersion.of(21)) + }) } \ No newline at end of file diff --git a/maps-compose/src/debug/AndroidManifest.xml b/maps-compose/src/debug/AndroidManifest.xml new file mode 100644 index 00000000..b106adac --- /dev/null +++ b/maps-compose/src/debug/AndroidManifest.xml @@ -0,0 +1,23 @@ + + + + + + + diff --git a/maps-compose/src/test/java/com/google/maps/android/compose/CameraPositionStateTest.kt b/maps-compose/src/test/java/com/google/maps/android/compose/CameraPositionStateTest.kt new file mode 100644 index 00000000..9f5757fe --- /dev/null +++ b/maps-compose/src/test/java/com/google/maps/android/compose/CameraPositionStateTest.kt @@ -0,0 +1,150 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.maps.android.compose + +import android.app.Activity +import android.os.Bundle +import com.google.android.gms.maps.CameraUpdateFactory +import com.google.android.gms.maps.GoogleMap +import com.google.android.gms.maps.MapView +import com.google.android.gms.maps.model.CameraPosition +import com.google.android.gms.maps.model.LatLng +import com.google.android.maps.robolectric.annotation.EnableMapsShadows +import com.google.android.maps.robolectric.shadows.ShadowGoogleMap +import com.google.android.maps.robolectric.truth.LatLngSubject +import com.google.common.truth.Truth.assertThat +import java.util.concurrent.atomic.AtomicReference +import kotlinx.coroutines.test.runTest +import org.junit.Before +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.shadow.api.Shadow +import org.robolectric.shadows.ShadowLooper + +// [START maps_compose_camera_position_state_test] +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34]) +@EnableMapsShadows +internal class CameraPositionStateTest { + + private lateinit var googleMap: GoogleMap + private lateinit var shadowMap: ShadowGoogleMap + + private val sydney: LatLng = LatLng(-33.852, 151.211) + private val tokyo: LatLng = LatLng(35.6762, 139.6503) + + @Before + internal fun setUp(): Unit { + val activity = Robolectric.buildActivity(Activity::class.java).create().get() + val mapView = MapView(activity) + mapView.onCreate(Bundle()) + + val mapRef = AtomicReference() + mapView.getMapAsync { mapRef.set(it) } + ShadowLooper.idleMainLooper() + + googleMap = mapRef.get() + shadowMap = Shadow.extract(googleMap) as ShadowGoogleMap + } + + @Test + internal fun testInitialPosition_withoutMapBound(): Unit { + val state = CameraPositionState(position = CameraPosition.fromLatLngZoom(sydney, 10f)) + assertThat(state.position.target).isEqualTo(sydney) + assertThat(state.position.zoom).isEqualTo(10f) + assertThat(state.isMoving).isFalse() + assertThat(state.projection).isNull() + } + + @Test + internal fun testSetMap_syncsPositionFromStateToMap(): Unit { + val initialPosition = CameraPosition.fromLatLngZoom(sydney, 12f) + val state = CameraPositionState(position = initialPosition) + + state.setMap(googleMap) + + assertThat(googleMap.cameraPosition.target).isEqualTo(sydney) + assertThat(googleMap.cameraPosition.zoom).isEqualTo(12f) + assertThat(state.projection).isNotNull() + } + + private fun bindState(state: CameraPositionState) { + state.setMap(googleMap) + googleMap.setOnCameraMoveStartedListener { reason -> + state.cameraMoveStartedReason = CameraMoveStartedReason.fromInt(reason) + state.isMoving = true + } + googleMap.setOnCameraMoveListener { + state.rawPosition = googleMap.cameraPosition + } + googleMap.setOnCameraIdleListener { + state.isMoving = false + state.rawPosition = googleMap.cameraPosition + } + } + + @Test + internal fun testMove_instantaneouslyUpdatesCameraPosition(): Unit { + val state = CameraPositionState() + bindState(state) + + state.move(CameraUpdateFactory.newLatLngZoom(tokyo, 14f)) + + assertThat(googleMap.cameraPosition.target).isEqualTo(tokyo) + LatLngSubject.assertThat(state.position.target) + .isWithin(1.0) + .of(tokyo) + assertThat(state.position.zoom).isEqualTo(14f) + assertThat(state.isMoving).isFalse() + } + + @Test + internal fun testAnimate_updatesCameraPosition(): Unit = runTest { + val state = CameraPositionState() + bindState(state) + + state.animate(CameraUpdateFactory.newLatLngZoom(tokyo, 15f), durationMs = 1000) + + assertThat(googleMap.cameraPosition.target).isEqualTo(tokyo) + LatLngSubject.assertThat(state.position.target) + .isWithin(1.0) + .of(tokyo) + assertThat(state.position.zoom).isEqualTo(15f) + assertThat(state.isMoving).isFalse() + } + + @Test + internal fun testProjection_convertsCoordinates(): Unit { + val state = CameraPositionState() + state.setMap(googleMap) + + state.move(CameraUpdateFactory.newLatLngZoom(sydney, 10f)) + + val projection = state.projection + assertThat(projection).isNotNull() + val screenPoint = projection?.toScreenLocation(sydney) + assertThat(screenPoint).isNotNull() + val roundTripLatLng = projection?.fromScreenLocation(screenPoint!!) + LatLngSubject.assertThat(roundTripLatLng) + .isWithin(1.0) + .of(sydney) + } +} +// [END maps_compose_camera_position_state_test] diff --git a/maps-compose/src/test/java/com/google/maps/android/compose/GoogleMapTest.kt b/maps-compose/src/test/java/com/google/maps/android/compose/GoogleMapTest.kt new file mode 100644 index 00000000..edc28072 --- /dev/null +++ b/maps-compose/src/test/java/com/google/maps/android/compose/GoogleMapTest.kt @@ -0,0 +1,186 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.maps.android.compose + +import androidx.activity.ComponentActivity +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import com.google.android.gms.maps.GoogleMap +import com.google.android.gms.maps.model.CameraPosition +import com.google.android.gms.maps.model.LatLng +import com.google.android.maps.robolectric.annotation.EnableMapsShadows +import com.google.android.maps.robolectric.shadows.ShadowGoogleMap +import com.google.android.maps.robolectric.truth.LatLngSubject +import com.google.common.truth.Truth.assertThat +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import org.robolectric.shadow.api.Shadow + +// [START maps_compose_google_map_composable_test] +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34]) +@EnableMapsShadows +@OptIn(MapsComposeExperimentalApi::class) +internal class GoogleMapTest { + + @get:Rule + internal val composeTestRule: androidx.compose.ui.test.junit4.AndroidComposeTestRule, ComponentActivity> = + createAndroidComposeRule() + + private val sydney: LatLng = LatLng(-33.852, 151.211) + + @Test + internal fun testGoogleMap_rendersWithMarkersAndCircles(): Unit { + lateinit var cameraState: CameraPositionState + var underlyingMap: GoogleMap? = null + + composeTestRule.setContent { + cameraState = rememberCameraPositionState { + position = CameraPosition.fromLatLngZoom(sydney, 11f) + } + GoogleMap( + cameraPositionState = cameraState, + modifier = Modifier.fillMaxSize() + ) { + MapEffect(Unit) { map -> + underlyingMap = map + } + Marker( + state = rememberMarkerState(position = sydney), + title = "Sydney Flagship" + ) + Circle( + center = sydney, + radius = 1500.0 + ) + } + } + + composeTestRule.waitForIdle() + + assertThat(underlyingMap).isNotNull() + val shadowMap = Shadow.extract(underlyingMap) as ShadowGoogleMap + + // Verify camera position + LatLngSubject.assertThat(cameraState.position.target) + .isWithin(1.0) + .of(sydney) + assertThat(cameraState.position.zoom).isEqualTo(11f) + + // Verify Marker rendered via MapApplier + assertThat(shadowMap.markers).hasSize(1) + val marker = shadowMap.markers.first() + assertThat(marker.title).isEqualTo("Sydney Flagship") + LatLngSubject.assertThat(marker.position) + .isWithin(1.0) + .of(sydney) + + // Verify Circle rendered via MapApplier + assertThat(shadowMap.circles).hasSize(1) + val circle = shadowMap.circles.first() + assertThat(circle.radius).isEqualTo(1500.0) + LatLngSubject.assertThat(circle.center) + .isWithin(1.0) + .of(sydney) + } + + @Test + internal fun testGoogleMap_markerClickUpdatesComposeState(): Unit { + var underlyingMap: GoogleMap? = null + var markerClicked by mutableStateOf(false) + + composeTestRule.setContent { + val cameraState = rememberCameraPositionState { + position = CameraPosition.fromLatLngZoom(sydney, 10f) + } + GoogleMap( + cameraPositionState = cameraState, + modifier = Modifier.fillMaxSize() + ) { + MapEffect(Unit) { map -> + underlyingMap = map + } + Marker( + state = rememberMarkerState(position = sydney), + title = "Clickable Marker", + onClick = { + markerClicked = true + true + } + ) + } + } + + composeTestRule.waitForIdle() + + assertThat(underlyingMap).isNotNull() + val shadowMap = Shadow.extract(underlyingMap) as ShadowGoogleMap + val marker = shadowMap.markers.first() + + // Simulate user clicking on marker + shadowMap.clickMarker(marker) + composeTestRule.waitForIdle() + + assertThat(markerClicked).isTrue() + } + + @Test + internal fun testGoogleMap_dynamicRecompositionAddsAndRemovesMarker(): Unit { + var underlyingMap: GoogleMap? = null + var showMarker by mutableStateOf(true) + + composeTestRule.setContent { + val cameraState = rememberCameraPositionState { + position = CameraPosition.fromLatLngZoom(sydney, 10f) + } + GoogleMap( + cameraPositionState = cameraState, + modifier = Modifier.fillMaxSize() + ) { + MapEffect(Unit) { map -> + underlyingMap = map + } + if (showMarker) { + Marker( + state = rememberMarkerState(position = sydney), + title = "Conditional Marker" + ) + } + } + } + + composeTestRule.waitForIdle() + assertThat(underlyingMap).isNotNull() + val shadowMap = Shadow.extract(underlyingMap) as ShadowGoogleMap + assertThat(shadowMap.markers).hasSize(1) + + // Mutate Compose state to remove marker + showMarker = false + composeTestRule.waitForIdle() + + // Assert that the marker was dynamically removed from the map + assertThat(shadowMap.markers).isEmpty() + } +} +// [END maps_compose_google_map_composable_test] diff --git a/maps-compose/src/test/java/com/google/maps/android/compose/MapApplierTest.kt b/maps-compose/src/test/java/com/google/maps/android/compose/MapApplierTest.kt new file mode 100644 index 00000000..6fc97cc8 --- /dev/null +++ b/maps-compose/src/test/java/com/google/maps/android/compose/MapApplierTest.kt @@ -0,0 +1,197 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.maps.android.compose + +import android.app.Activity +import android.os.Bundle +import androidx.compose.runtime.CompositionContext +import com.google.android.gms.maps.GoogleMap +import com.google.android.gms.maps.MapView +import com.google.android.gms.maps.model.CircleOptions +import com.google.android.gms.maps.model.LatLng +import com.google.android.gms.maps.model.MarkerOptions +import com.google.android.maps.robolectric.annotation.EnableMapsShadows +import com.google.android.maps.robolectric.shadows.ShadowGoogleMap +import com.google.android.maps.robolectric.truth.LatLngSubject +import com.google.common.truth.Truth.assertThat +import io.mockk.mockk +import java.util.concurrent.atomic.AtomicReference +import org.junit.Before +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.shadow.api.Shadow +import org.robolectric.shadows.ShadowLooper + +// [START maps_compose_map_applier_test] +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [34]) +@EnableMapsShadows +internal class MapApplierTest { + + private lateinit var mapView: MapView + private lateinit var googleMap: GoogleMap + private lateinit var shadowMap: ShadowGoogleMap + private lateinit var applier: MapApplier + + private val sydney: LatLng = LatLng(-33.852, 151.211) + private val perth: LatLng = LatLng(-31.952, 115.857) + + @Before + internal fun setUp(): Unit { + val activity = Robolectric.buildActivity(Activity::class.java).create().get() + mapView = MapView(activity) + mapView.onCreate(Bundle()) + + val mapRef = AtomicReference() + mapView.getMapAsync { mapRef.set(it) } + ShadowLooper.idleMainLooper() + + googleMap = mapRef.get() + shadowMap = Shadow.extract(googleMap) as ShadowGoogleMap + applier = MapApplier(googleMap, mapView, MapClickListeners()) + } + + private fun createMarkerNode( + markerState: MarkerState, + onMarkerClick: (com.google.android.gms.maps.model.Marker) -> Boolean = { false }, + position: LatLng = sydney + ): MarkerNode { + val marker = googleMap.addMarker(MarkerOptions().position(position).title("Test Marker"))!! + val dummyContext: CompositionContext = mockk(relaxed = true) + return MarkerNode( + compositionContext = dummyContext, + marker = marker, + markerState = markerState, + onMarkerClick = onMarkerClick, + onInfoWindowClick = {}, + onInfoWindowClose = {}, + onInfoWindowLongClick = {}, + infoWindow = null, + infoContent = null, + ) + } + + @Test + internal fun testInsertMarkerNode_attachesAndSyncsMarkerState(): Unit { + val markerState = MarkerState(sydney) + val node = createMarkerNode(markerState) + + applier.insertBottomUp(0, node) + + assertThat(markerState.marker).isSameInstanceAs(node.marker) + assertThat(shadowMap.markers).contains(node.marker) + } + + @Test + internal fun testRemoveMarkerNode_clearsMarkerStateAndRemovesFromMap(): Unit { + val markerState = MarkerState(sydney) + val node = createMarkerNode(markerState) + + applier.insertBottomUp(0, node) + assertThat(shadowMap.markers).hasSize(1) + + applier.remove(0, 1) + + assertThat(markerState.marker).isNull() + assertThat(shadowMap.markers).isEmpty() + } + + @Test + internal fun testMarkerClick_dispatchesToNodeCallback(): Unit { + val markerState = MarkerState(sydney) + var clickCount = 0 + val node = createMarkerNode( + markerState = markerState, + onMarkerClick = { + clickCount++ + true + } + ) + + applier.insertBottomUp(0, node) + + // Simulate marker click via shadow + shadowMap.clickMarker(node.marker) + + assertThat(clickCount).isEqualTo(1) + } + + @Test + internal fun testMarkerDrag_updatesMarkerStatePosition(): Unit { + val markerState = MarkerState(sydney) + val node = createMarkerNode(markerState) + node.marker.isDraggable = true + + applier.insertBottomUp(0, node) + + // Drag marker to Perth via shadow + shadowMap.dragMarkerStart(node.marker) + assertThat(markerState.isDragging).isTrue() + + shadowMap.dragMarker(node.marker, perth) + LatLngSubject.assertThat(markerState.position).isWithin(1.0).of(perth) + + shadowMap.dragMarkerEnd(node.marker, perth) + assertThat(markerState.isDragging).isFalse() + LatLngSubject.assertThat(markerState.position).isWithin(1.0).of(perth) + } + + @Test + internal fun testCircleNode_clickAndRemoval(): Unit { + val circle = googleMap.addCircle(CircleOptions().center(sydney).radius(500.0).clickable(true)) + var circleClicked = false + val circleNode = CircleNode( + circle = circle, + onCircleClick = { circleClicked = true } + ) + + applier.insertBottomUp(0, circleNode) + assertThat(shadowMap.circles).contains(circle) + + // Simulate click via shadow + shadowMap.clickCircle(circle) + assertThat(circleClicked).isTrue() + + // Remove node + applier.remove(0, 1) + assertThat(shadowMap.circles).isEmpty() + } + + @Test + internal fun testOnClear_removesAllDecorations(): Unit { + val markerState = MarkerState(sydney) + val markerNode = createMarkerNode(markerState) + val circle = googleMap.addCircle(CircleOptions().center(sydney).radius(500.0)) + val circleNode = CircleNode(circle, onCircleClick = {}) + + applier.insertBottomUp(0, markerNode) + applier.insertBottomUp(1, circleNode) + + assertThat(shadowMap.markers).hasSize(1) + assertThat(shadowMap.circles).hasSize(1) + + applier.clear() + + assertThat(shadowMap.markers).isEmpty() + assertThat(shadowMap.circles).isEmpty() + assertThat(markerState.marker).isNull() + } +} +// [END maps_compose_map_applier_test] diff --git a/repo/com/google/android/maps/robolectric/shadows/1.0.0/shadows-1.0.0.aar b/repo/com/google/android/maps/robolectric/shadows/1.0.0/shadows-1.0.0.aar new file mode 100644 index 00000000..637d9710 Binary files /dev/null and b/repo/com/google/android/maps/robolectric/shadows/1.0.0/shadows-1.0.0.aar differ diff --git a/repo/com/google/android/maps/robolectric/shadows/1.0.0/shadows-1.0.0.module b/repo/com/google/android/maps/robolectric/shadows/1.0.0/shadows-1.0.0.module new file mode 100644 index 00000000..8c651d71 --- /dev/null +++ b/repo/com/google/android/maps/robolectric/shadows/1.0.0/shadows-1.0.0.module @@ -0,0 +1,116 @@ +{ + "formatVersion": "1.1", + "component": { + "group": "com.google.android.maps.robolectric", + "module": "shadows", + "version": "1.0.0", + "attributes": { + "org.gradle.status": "release" + } + }, + "createdBy": { + "gradle": { + "version": "9.1.0" + } + }, + "variants": [ + { + "name": "releaseVariantReleaseApiPublication", + "attributes": { + "org.gradle.category": "library", + "org.gradle.dependency.bundling": "external", + "org.gradle.libraryelements": "aar", + "org.gradle.usage": "java-api" + }, + "dependencies": [ + { + "group": "org.jetbrains.kotlin", + "module": "kotlin-stdlib", + "version": { + "requires": "2.3.20" + } + } + ], + "files": [ + { + "name": "shadows-1.0.0.aar", + "url": "shadows-1.0.0.aar", + "size": 50521, + "sha512": "be8db1c9b97ded5b3b7598ab58d223df837bcede822c89be78cbc1cd40a93e803f50555479e0c392820214c2ea8dd34864c4686bf3d9c02ed0a1bc77b11b824f", + "sha256": "17a2cdbf2948a18133acaaad74145e542b091efc85b154aae47e48829a4f2bb5", + "sha1": "379b67474c7045fa5c5bc1ede172390ce40fe075", + "md5": "665f37deca4f4c7eacd22e65291bca63" + } + ] + }, + { + "name": "releaseVariantReleaseRuntimePublication", + "attributes": { + "org.gradle.category": "library", + "org.gradle.dependency.bundling": "external", + "org.gradle.libraryelements": "aar", + "org.gradle.usage": "java-runtime" + }, + "dependencies": [ + { + "group": "org.jetbrains.kotlin", + "module": "kotlin-stdlib", + "version": { + "requires": "2.3.20" + } + } + ], + "files": [ + { + "name": "shadows-1.0.0.aar", + "url": "shadows-1.0.0.aar", + "size": 50521, + "sha512": "be8db1c9b97ded5b3b7598ab58d223df837bcede822c89be78cbc1cd40a93e803f50555479e0c392820214c2ea8dd34864c4686bf3d9c02ed0a1bc77b11b824f", + "sha256": "17a2cdbf2948a18133acaaad74145e542b091efc85b154aae47e48829a4f2bb5", + "sha1": "379b67474c7045fa5c5bc1ede172390ce40fe075", + "md5": "665f37deca4f4c7eacd22e65291bca63" + } + ] + }, + { + "name": "releaseVariantReleaseSourcePublication", + "attributes": { + "org.gradle.category": "documentation", + "org.gradle.dependency.bundling": "external", + "org.gradle.docstype": "sources", + "org.gradle.usage": "java-runtime" + }, + "files": [ + { + "name": "shadows-1.0.0-sources.jar", + "url": "shadows-1.0.0-sources.jar", + "size": 31416, + "sha512": "3f1714d5f352dc5996d90c0ace16f38566253fe3b49f1b8d24e444571750b6e5039c0631463a92cb3cea7c5f9ac90e2096e4e66272899d627dea3a82542f6783", + "sha256": "b442bdd6c6ac88128058c5af4a28288b827432731a68624012764d15973972c0", + "sha1": "563b547330cd1701f1a1f15b39cde1fa73554aa0", + "md5": "cd96d340bf7af4bea40b4f9631959fc6" + } + ] + }, + { + "name": "releaseVariantReleaseJavaDocPublication", + "attributes": { + "org.gradle.category": "documentation", + "org.gradle.dependency.bundling": "external", + "org.gradle.docstype": "javadoc", + "org.gradle.usage": "java-runtime" + }, + "files": [ + { + "name": "shadows-1.0.0-javadoc.jar", + "url": "shadows-1.0.0-javadoc.jar", + "size": 358915, + "sha512": "5ed9457edc6b3f24cdc7db19a7b3a5cb49d34322c18e81a47b7a21ba1587a053571a33a34ecda00950723fa5b700cbe775a828434499f1e5c7b93b32d3a9e54c", + "sha256": "b5ce9bfff24d3efab5eadc18d70ce3b9d61733e7b562aae078cbc9163435d4bd", + "sha1": "d0f4bcddae95c27f268fc77fc9e062b90e845448", + "md5": "1d822db43393004267bb9f11eb4d62dc" + } + ] + } + ] +} diff --git a/repo/com/google/android/maps/robolectric/shadows/1.0.0/shadows-1.0.0.pom b/repo/com/google/android/maps/robolectric/shadows/1.0.0/shadows-1.0.0.pom new file mode 100644 index 00000000..e5068d5c --- /dev/null +++ b/repo/com/google/android/maps/robolectric/shadows/1.0.0/shadows-1.0.0.pom @@ -0,0 +1,41 @@ + + + + + + + + 4.0.0 + com.google.android.maps.robolectric + shadows + 1.0.0 + aar + Android Maps Robolectric Shadows + Robolectric shadows and Truth testing utilities for Google Maps SDK on Android. + https://github.com/googlemaps/android-maps-robolectric + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + + + + + Google Maps Platform Developer Relations + + + + scm:git:github.com/googlemaps/android-maps-robolectric.git + scm:git:ssh://github.com/googlemaps/android-maps-robolectric.git + https://github.com/googlemaps/android-maps-robolectric/tree/main + + + + org.jetbrains.kotlin + kotlin-stdlib + 2.3.20 + compile + + + diff --git a/settings.gradle.kts b/settings.gradle.kts index e0b1768c..cf66485c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -17,6 +17,9 @@ dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { + maven { + url = uri(rootDir.resolve("repo")) + } if (providers.gradleProperty("useMavenLocal").orNull == "true" || providers.environmentVariable("USE_MAVEN_LOCAL").orNull == "true") { mavenLocal()