From 303b6156772e9c6a95c18526a09f9f87c05454d8 Mon Sep 17 00:00:00 2001 From: quimodotcom Date: Wed, 10 Jun 2026 21:20:38 +0100 Subject: [PATCH 1/3] Update CreatorImpl.java --- .../gms/maps/internal/CreatorImpl.java | 50 ++++++++++--------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/play-services-maps/core/vtm/src/main/java/com/google/android/gms/maps/internal/CreatorImpl.java b/play-services-maps/core/vtm/src/main/java/com/google/android/gms/maps/internal/CreatorImpl.java index b7dcd828dc..9bc565e86f 100644 --- a/play-services-maps/core/vtm/src/main/java/com/google/android/gms/maps/internal/CreatorImpl.java +++ b/play-services-maps/core/vtm/src/main/java/com/google/android/gms/maps/internal/CreatorImpl.java @@ -21,9 +21,8 @@ import android.content.res.Resources; import android.os.Parcel; import android.os.RemoteException; -import android.util.Log; - import androidx.annotation.Keep; +import android.util.Log; import com.google.android.gms.dynamic.IObjectWrapper; import com.google.android.gms.dynamic.ObjectWrapper; @@ -31,66 +30,69 @@ import com.google.android.gms.maps.StreetViewPanoramaOptions; import com.google.android.gms.maps.model.internal.IBitmapDescriptorFactoryDelegate; -import org.microg.gms.maps.vtm.MapFragmentImpl; -import org.microg.gms.maps.vtm.MapViewImpl; -import org.microg.gms.maps.vtm.ResourcesContainer; -import org.microg.gms.maps.vtm.StreetViewPanoramaFragmentImpl; -import org.microg.gms.maps.vtm.StreetViewPanoramaViewImpl; -import org.microg.gms.maps.vtm.bitmap.BitmapDescriptorFactoryImpl; -import org.microg.gms.maps.vtm.camera.CameraUpdateFactoryImpl; +import org.microg.gms.maps.mapbox.CameraUpdateFactoryImpl; +import org.microg.gms.maps.mapbox.MapFragmentImpl; +import org.microg.gms.maps.mapbox.MapViewImpl; +import org.microg.gms.maps.mapbox.StylesKt; +import org.microg.gms.maps.mapbox.StreetViewPanoramaFragmentImpl; +import org.microg.gms.maps.mapbox.StreetViewPanoramaViewImpl; +import org.microg.gms.maps.mapbox.model.BitmapDescriptorFactoryImpl; @Keep public class CreatorImpl extends ICreator.Stub { private static final String TAG = "GmsMapCreator"; @Override - public void init(IObjectWrapper resources) throws RemoteException { + public void init(IObjectWrapper resources) { initV2(resources, 0); } @Override - public IMapFragmentDelegate newMapFragmentDelegate(IObjectWrapper activity) throws RemoteException { - return new MapFragmentImpl((Activity) ObjectWrapper.unwrap(activity)); + public IMapFragmentDelegate newMapFragmentDelegate(IObjectWrapper activity) { + return new MapFragmentImpl(ObjectWrapper.unwrapTyped(activity, Activity.class)); } @Override - public IMapViewDelegate newMapViewDelegate(IObjectWrapper context, GoogleMapOptions options) throws RemoteException { - return new MapViewImpl((Context) ObjectWrapper.unwrap(context), options); + public IMapViewDelegate newMapViewDelegate(IObjectWrapper context, GoogleMapOptions options) { + return new MapViewImpl(ObjectWrapper.unwrapTyped(context, Context.class), options); } @Override - public ICameraUpdateFactoryDelegate newCameraUpdateFactoryDelegate() throws RemoteException { - return CameraUpdateFactoryImpl.get(); + public ICameraUpdateFactoryDelegate newCameraUpdateFactoryDelegate() { + return new CameraUpdateFactoryImpl(); } @Override - public IBitmapDescriptorFactoryDelegate newBitmapDescriptorFactoryDelegate() throws RemoteException { - return new BitmapDescriptorFactoryImpl(); + public IBitmapDescriptorFactoryDelegate newBitmapDescriptorFactoryDelegate() { + return BitmapDescriptorFactoryImpl.INSTANCE; } @Override - public void initV2(IObjectWrapper resources, int flags) throws RemoteException { - ResourcesContainer.set((Resources) ObjectWrapper.unwrap(resources)); + public void initV2(IObjectWrapper resources, int flags) { + BitmapDescriptorFactoryImpl.INSTANCE.initialize(ObjectWrapper.unwrapTyped(resources, Resources.class), null); + //ResourcesContainer.set((Resources) ObjectWrapper.unwrap(resources)); + Log.d(TAG, "initV2 " + flags); } @Override public IStreetViewPanoramaViewDelegate newStreetViewPanoramaViewDelegate(IObjectWrapper context, StreetViewPanoramaOptions options) { - return new StreetViewPanoramaViewImpl((Activity) ObjectWrapper.unwrap(context)); + return new StreetViewPanoramaViewImpl(ObjectWrapper.unwrapTyped(context, Context.class)); } @Override public IStreetViewPanoramaFragmentDelegate newStreetViewPanoramaFragmentDelegate(IObjectWrapper activity) { - return new StreetViewPanoramaFragmentImpl((Activity) ObjectWrapper.unwrap(activity)); + return new StreetViewPanoramaFragmentImpl(ObjectWrapper.unwrapTyped(activity, Activity.class)); } @Override public int getRendererType() throws RemoteException { - return 1; + if (!StylesKt.hasAnyMapKey()) return 0; + return 2; } @Override public void logInitialization(IObjectWrapper context, int preferredRenderer) throws RemoteException { - Log.d(TAG, "VTM-based Map initialized (preferred renderer was " + preferredRenderer + ")"); + Log.d(TAG, "Mapbox-based Map initialized (preferred renderer was " + preferredRenderer + ")"); } @Override From 98738ec5bdbba19d8669095f011b58e296274bd3 Mon Sep 17 00:00:00 2001 From: Evan Donald Date: Wed, 10 Jun 2026 21:22:25 +0100 Subject: [PATCH 2/3] add kotlin bypass/dummy impl --- .../gms/maps/mapbox/DummyGoogleMapImpl.kt | 108 ++++++++++++++++++ .../org/microg/gms/maps/mapbox/Styles.kt | 13 ++- 2 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/DummyGoogleMapImpl.kt diff --git a/play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/DummyGoogleMapImpl.kt b/play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/DummyGoogleMapImpl.kt new file mode 100644 index 0000000000..8ffb91f96b --- /dev/null +++ b/play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/DummyGoogleMapImpl.kt @@ -0,0 +1,108 @@ +package org.microg.gms.maps.mapbox + +import android.content.Context +import android.location.Location +import android.os.Bundle +import android.os.Parcel +import android.util.Log +import android.view.View +import android.widget.FrameLayout +import com.google.android.gms.dynamic.IObjectWrapper +import com.google.android.gms.dynamic.ObjectWrapper +import com.google.android.gms.maps.internal.* +import com.google.android.gms.maps.model.* +import com.google.android.gms.maps.model.internal.* +import org.microg.gms.maps.mapbox.model.AbstractMarker + +class DummyMarkerImpl(private val id: String, options: MarkerOptions) : IMarkerDelegate.Stub() { + private var position = options.position + override fun remove() {} + override fun getId(): String = id + override fun setPosition(pos: LatLng?) { position = pos ?: position } + override fun getPosition(): LatLng = position + override fun setTitle(title: String?) {} + override fun getTitle(): String? = null + override fun setSnippet(snippet: String?) {} + override fun getSnippet(): String? = null + override fun setDraggable(drag: Boolean) {} + override fun isDraggable(): Boolean = false + override fun showInfoWindow() {} + override fun hideInfoWindow() {} + override fun isInfoWindowShown(): Boolean = false + override fun setVisible(visible: Boolean) {} + override fun isVisible(): Boolean = true + override fun equalsRemote(other: IMarkerDelegate?): Boolean = other?.id == id + override fun hashCodeRemote(): Int = id.hashCode() + override fun setIcon(obj: IObjectWrapper?) {} + override fun setAnchor(x: Float, y: Float) {} + override fun setFlat(flat: Boolean) {} + override fun isFlat(): Boolean = false + override fun setRotation(rotation: Float) {} + override fun getRotation(): Float = 0f + override fun setInfoWindowAnchor(x: Float, y: Float) {} + override fun setAlpha(alpha: Float) {} + override fun getAlpha(): Float = 1f + override fun setZIndex(zIndex: Float) {} + override fun getZIndex(): Float = 0f + override fun setTag(obj: IObjectWrapper?) {} + override fun getTag(): IObjectWrapper = ObjectWrapper.wrap(null) +} + +class DummyGoogleMapImpl(context: Context) : AbstractGoogleMap(context) { + val view: View = FrameLayout(mapContext) + private var markerId = 0 + + override fun getCameraPosition(): CameraPosition = CameraPosition(LatLng(0.0, 0.0), 0f, 0f, 0f) + override fun getMaxZoomLevel(): Float = 20f + override fun getMinZoomLevel(): Float = 0f + override fun moveCamera(cameraUpdate: IObjectWrapper?) {} + override fun animateCamera(cameraUpdate: IObjectWrapper?) {} + override fun animateCameraWithCallback(cameraUpdate: IObjectWrapper?, callback: ICancelableCallback?) { callback?.onFinish() } + override fun animateCameraWithDurationAndCallback(cameraUpdate: IObjectWrapper?, duration: Int, callback: ICancelableCallback?) { callback?.onFinish() } + override fun stopAnimation() {} + override fun setMapStyle(options: MapStyleOptions?): Boolean = true + override fun setMinZoomPreference(minZoom: Float) {} + override fun setMaxZoomPreference(maxZoom: Float) {} + override fun resetMinMaxZoomPreference() {} + override fun setLatLngBoundsForCameraTarget(bounds: LatLngBounds?) {} + override fun addPolyline(options: PolylineOptions): IPolylineDelegate? = null + override fun addPolygon(options: PolygonOptions): IPolygonDelegate? = null + override fun addMarker(options: MarkerOptions): IMarkerDelegate = DummyMarkerImpl("m${markerId++}", options) + override fun addGroundOverlay(options: GroundOverlayOptions): IGroundOverlayDelegate? = null + override fun addTileOverlay(options: TileOverlayOptions): ITileOverlayDelegate? = null + override fun addCircle(options: CircleOptions): ICircleDelegate? = null + override fun clear() {} + override fun getMapType(): Int = 0 + override fun setMapType(type: Int) {} + override fun setWatermarkEnabled(watermark: Boolean) {} + override fun isMyLocationEnabled(): Boolean = false + override fun setMyLocationEnabled(myLocation: Boolean) {} + override fun setLocationSource(locationSource: ILocationSourceDelegate?) {} + override fun getMyLocation(): Location? = null + override fun onLocationUpdate(location: Location) {} + override fun setContentDescription(desc: String?) {} + override fun getUiSettings(): IUiSettingsDelegate = UiSettingsCache() + override fun getProjection(): IProjectionDelegate = DummyProjection() + override fun setOnCameraChangeListener(listener: IOnCameraChangeListener?) {} + override fun setOnMarkerDragListener(listener: IOnMarkerDragListener?) {} + override fun snapshot(callback: ISnapshotReadyCallback, bitmap: IObjectWrapper?) { callback.onBitmapWrappedReady(ObjectWrapper.wrap(null)) } + override fun snapshotForTest(callback: ISnapshotReadyCallback?) {} + override fun setPadding(left: Int, top: Int, right: Int, bottom: Int) {} + override fun setOnMapLoadedCallback(callback: IOnMapLoadedCallback?) { callback?.onMapLoaded() } + override fun setCameraMoveStartedListener(listener: IOnCameraMoveStartedListener?) {} + override fun setCameraMoveListener(listener: IOnCameraMoveListener?) {} + override fun setCameraMoveCanceledListener(listener: IOnCameraMoveCanceledListener?) {} + override fun setCameraIdleListener(listener: IOnCameraIdleListener?) {} + override fun onCreate(savedInstanceState: Bundle?) {} + override fun onResume() {} + override fun onPause() {} + override fun onDestroy() {} + override fun onStart() {} + override fun onStop() {} + override fun onLowMemory() {} + override fun onSaveInstanceState(outState: Bundle) {} + override fun showInfoWindow(marker: AbstractMarker): Boolean = false + fun getMapAsync(callback: IOnMapReadyCallback) { callback.onMapReady(this) } + override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = + if (super.onTransact(code, data, reply, flags)) true else { Log.d("GmsMapDummy", "onTransact [unknown]: $code, $data, $flags"); false } +} diff --git a/play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/Styles.kt b/play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/Styles.kt index a3542fe0b4..2d4aab4061 100644 --- a/play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/Styles.kt +++ b/play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/Styles.kt @@ -38,14 +38,23 @@ const val KEY_LAYER_PAINT = "paint" const val KEY_SOURCE_URL = "url" const val KEY_SOURCE_TILES = "tiles" +fun hasAnyMapKey(): Boolean { + val mapboxKey = BuildConfig.MAPBOX_KEY + val stadiaKey = BuildConfig.STADIA_KEY + return !(mapboxKey.isNullOrEmpty() || mapboxKey == "null" || mapboxKey == "YOUR_KEY_HERE") || + !(stadiaKey.isNullOrEmpty() || stadiaKey == "null" || stadiaKey == "YOUR_KEY_HERE") +} fun getStyle( context: MapContext, mapType: Int, styleOptions: MapStyleOptions?, styleFromFileWorkaround: Boolean = false ): Style.Builder { + if (!hasAnyMapKey()) { + return Style.Builder().fromJson("{\"version\": 8, \"sources\": {}, \"layers\": []}") + } val styleJson = JSONObject( context.assets.open( - if (BuildConfig.STADIA_KEY.isNotEmpty()) when (mapType) { + if (BuildConfig.STADIA_KEY.isNotEmpty() && BuildConfig.STADIA_KEY != "null" && BuildConfig.STADIA_KEY != "YOUR_KEY_HERE") when (mapType) { GoogleMap.MAP_TYPE_SATELLITE, GoogleMap.MAP_TYPE_HYBRID -> "style-microg-satellite-stadia.json" GoogleMap.MAP_TYPE_TERRAIN -> "style-stadia-outdoors.json" //MAP_TYPE_NONE, MAP_TYPE_NORMAL, @@ -60,7 +69,7 @@ fun getStyle( ) // Inject API key - if (BuildConfig.STADIA_KEY.isNotEmpty()) { + if (BuildConfig.STADIA_KEY.isNotEmpty() && BuildConfig.STADIA_KEY != "null" && BuildConfig.STADIA_KEY != "YOUR_KEY_HERE") { val sourceArray = styleJson.getJSONObject(KEY_SOURCES) for (key in sourceArray.keys()) { val sourceObject = sourceArray.getJSONObject(key) From e8f8d08d212cadd2dee3b03ca8f3a964c14c6fed Mon Sep 17 00:00:00 2001 From: Evan Donald Date: Wed, 10 Jun 2026 21:25:12 +0100 Subject: [PATCH 3/3] pt2 fixes and changes --- .../kotlin/org/microg/gms/maps/mapbox/GoogleMap.kt | 4 +++- .../kotlin/org/microg/gms/maps/mapbox/LiteGoogleMap.kt | 8 +++++++- .../kotlin/org/microg/gms/maps/mapbox/MapFragment.kt | 10 ++++++++-- .../main/kotlin/org/microg/gms/maps/mapbox/MapView.kt | 6 +++++- 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/GoogleMap.kt b/play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/GoogleMap.kt index e542fb6a53..b0d0ec0d6b 100644 --- a/play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/GoogleMap.kt +++ b/play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/GoogleMap.kt @@ -132,7 +132,9 @@ class GoogleMapImpl(context: Context, var options: GoogleMapOptions) : AbstractG BitmapDescriptorFactoryImpl.initialize(mapContext.resources, context.resources) LibraryLoader.setLibraryLoader(MultiArchLoader(mapContext, context)) runOnMainLooper { - Mapbox.getInstance(mapContext, BuildConfig.MAPBOX_KEY, WellKnownTileServer.Mapbox) + if (hasAnyMapKey()) { + Mapbox.getInstance(mapContext, BuildConfig.MAPBOX_KEY, WellKnownTileServer.Mapbox) + } } diff --git a/play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/LiteGoogleMap.kt b/play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/LiteGoogleMap.kt index f4395633c6..6cf043708b 100644 --- a/play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/LiteGoogleMap.kt +++ b/play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/LiteGoogleMap.kt @@ -206,7 +206,9 @@ class LiteGoogleMapImpl(context: Context, var options: GoogleMapOptions) : Abstr override fun onCreate(savedInstanceState: Bundle?) { if (!created) { - Mapbox.getInstance(mapContext, BuildConfig.MAPBOX_KEY, WellKnownTileServer.Mapbox) + if (hasAnyMapKey()) { + Mapbox.getInstance(mapContext, BuildConfig.MAPBOX_KEY, WellKnownTileServer.Mapbox) + } if (savedInstanceState?.containsKey(BUNDLE_CAMERA_POSITION) == true) { cameraPosition = savedInstanceState.getParcelable(BUNDLE_CAMERA_POSITION)!! @@ -230,6 +232,10 @@ class LiteGoogleMapImpl(context: Context, var options: GoogleMapOptions) : Abstr @UiThread private fun updateSnapshot() { + if (!hasAnyMapKey()) { + Log.d(TAG, "Skipping snapshot update as no API keys are provided") + return + } val cameraPosition = cameraPosition val dpi = dpiFactor diff --git a/play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/MapFragment.kt b/play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/MapFragment.kt index 69135ab299..466d719d59 100644 --- a/play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/MapFragment.kt +++ b/play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/MapFragment.kt @@ -53,7 +53,9 @@ class MapFragmentImpl(private val activity: Activity) : IMapFragmentDelegate.Stu if (options == null) { options = GoogleMapOptions() } - if (options?.liteMode == true) { + if (!hasAnyMapKey()) { + map = DummyGoogleMapImpl(activity) + } else if (options?.liteMode == true) { map = LiteGoogleMapImpl(activity, options ?: GoogleMapOptions()) } else { map = GoogleMapImpl(activity, options ?: GoogleMapOptions()) @@ -66,7 +68,9 @@ class MapFragmentImpl(private val activity: Activity) : IMapFragmentDelegate.Stu } Log.d(TAG, "onCreateView: ${options?.camera?.target}") if (map == null) { - map = if (options?.liteMode == true) { + map = if (!hasAnyMapKey()) { + DummyGoogleMapImpl(activity) + } else if (options?.liteMode == true) { LiteGoogleMapImpl(activity, options ?: GoogleMapOptions()) } else { GoogleMapImpl(activity, options ?: GoogleMapOptions()) @@ -78,6 +82,7 @@ class MapFragmentImpl(private val activity: Activity) : IMapFragmentDelegate.Stu val view = when (this) { is GoogleMapImpl -> this.view is LiteGoogleMapImpl -> this.view + is DummyGoogleMapImpl -> this.view else -> null } @@ -99,6 +104,7 @@ class MapFragmentImpl(private val activity: Activity) : IMapFragmentDelegate.Stu override fun getMapAsync(callback: IOnMapReadyCallback) = map?.let { if (it is GoogleMapImpl) it.getMapAsync(callback) else if (it is LiteGoogleMapImpl) it.getMapAsync(callback) + else if (it is DummyGoogleMapImpl) it.getMapAsync(callback) } ?: Unit override fun onDestroyView() { diff --git a/play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/MapView.kt b/play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/MapView.kt index ec3231a6fd..a98dc02da5 100644 --- a/play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/MapView.kt +++ b/play-services-maps/core/mapbox/src/main/kotlin/org/microg/gms/maps/mapbox/MapView.kt @@ -34,7 +34,9 @@ class MapViewImpl(private val context: Context, options: GoogleMapOptions?) : IM override fun onCreate(savedInstanceState: Bundle?) { Log.d(TAG, "onCreate: ${options?.camera?.target}") - map = if (options.liteMode) { + map = if (!hasAnyMapKey()) { + DummyGoogleMapImpl(context) + } else if (options.liteMode) { LiteGoogleMapImpl(context, options) } else { GoogleMapImpl(context, options) @@ -62,6 +64,7 @@ class MapViewImpl(private val context: Context, options: GoogleMapOptions?) : IM when (it) { is GoogleMapImpl -> it.view is LiteGoogleMapImpl -> it.view + is DummyGoogleMapImpl -> it.view else -> null } } @@ -71,6 +74,7 @@ class MapViewImpl(private val context: Context, options: GoogleMapOptions?) : IM when (it) { is GoogleMapImpl -> it.getMapAsync(callback) is LiteGoogleMapImpl -> it.getMapAsync(callback) + is DummyGoogleMapImpl -> it.getMapAsync(callback) else -> null } } ?: Unit