diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 4408567ef5e..ad909a4da56 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -40,6 +40,8 @@ val selectableVariants = listOf(
"playProdBenchmark",
"playProdInstrumentation",
"playProdRelease",
+ "playFossProdRelease",
+ "playGmsProdRelease",
"playStagingDebug",
"playStagingCanary",
"playStagingSpinner",
@@ -81,7 +83,7 @@ android {
buildToolsVersion = signalBuildToolsVersion
compileSdkVersion = signalCompileSdkVersion
- flavorDimensions += listOf("distribution", "environment")
+ flavorDimensions += listOf("distribution", "gms", "environment")
useLibrary("org.apache.http.legacy")
testBuildType = "instrumentation"
@@ -352,6 +354,17 @@ android {
buildConfigField("String", "BUILD_DISTRIBUTION_TYPE", "\"nightly\"")
}
+ create("gms") {
+ dimension = "gms"
+ isDefault = true
+ buildConfigField("boolean", "USE_OSM", "false")
+ }
+
+ create("foss") {
+ dimension = "gms"
+ buildConfigField("boolean", "USE_OSM", "true")
+ }
+
create("prod") {
dimension = "environment"
@@ -508,13 +521,15 @@ dependencies {
implementation(libs.androidx.asynclayoutinflater)
implementation(libs.androidx.asynclayoutinflater.appcompat)
implementation(libs.androidx.emoji2)
- implementation(libs.firebase.messaging) {
+ "gmsImplementation"(libs.firebase.messaging) {
exclude(group = "com.google.firebase", module = "firebase-core")
exclude(group = "com.google.firebase", module = "firebase-analytics")
exclude(group = "com.google.firebase", module = "firebase-measurement-connector")
}
- implementation(libs.google.play.services.maps)
- implementation(libs.google.play.services.auth)
+ "gmsImplementation"(libs.google.play.services.maps)
+ "gmsImplementation"(libs.google.play.services.auth)
+ "fossImplementation"(project(":libfakegms"))
+ "fossImplementation"(libs.osmdroid)
implementation(libs.bundles.media3)
implementation(libs.conscrypt.android)
implementation(libs.signal.aesgcmprovider)
@@ -551,7 +566,7 @@ dependencies {
implementation(libs.accompanist.permissions)
implementation(libs.kotlin.stdlib.jdk8)
implementation(libs.kotlin.reflect)
- implementation(libs.kotlinx.coroutines.play.services)
+ "gmsImplementation"(libs.kotlinx.coroutines.play.services)
implementation(libs.jackson.module.kotlin)
implementation(libs.rxjava3.rxandroid)
implementation(libs.rxjava3.rxkotlin)
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/location/SignalPlace.java b/app/src/main/java/org/thoughtcrime/securesms/components/location/SignalPlace.java
index 70035a073ab..d3c65b7bda4 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/location/SignalPlace.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/location/SignalPlace.java
@@ -11,6 +11,7 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.android.gms.maps.model.LatLng;
+import org.thoughtcrime.securesms.BuildConfig;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.maps.AddressData;
import org.thoughtcrime.securesms.util.JsonUtils;
@@ -19,7 +20,8 @@
public class SignalPlace {
- private static final String URL = "https://maps.google.com/maps";
+ private static final String GMS_URL = "https://maps.google.com/maps";
+ private static final String OSM_URL = "https://www.openstreetmap.org/";
private static final String TAG = Log.tag(SignalPlace.class);
@JsonProperty
@@ -62,10 +64,21 @@ public String getDescription() {
description += (address + "\n");
}
- description += Uri.parse(URL)
- .buildUpon()
- .appendQueryParameter("q", String.format("%s,%s", latitude, longitude))
- .build().toString();
+ if (BuildConfig.USE_OSM) {
+ // Thanks to https://github.com/sergimn for suggesting place marker
+ description += Uri.parse(OSM_URL)
+ .buildUpon()
+ .appendQueryParameter("mlat", String.format("%s", latitude))
+ .appendQueryParameter("mlon", String.format("%s", longitude))
+ .encodedFragment(String.format("map=15/%s/%s", latitude, longitude))
+ .build().toString();
+ }
+ else {
+ description += Uri.parse(GMS_URL)
+ .buildUpon()
+ .appendQueryParameter("q", String.format("%s,%s", latitude, longitude))
+ .build().toString();
+ }
return description;
}
diff --git a/dependencies.gradle.kts b/dependencies.gradle.kts
index 65beb937c99..0b98ecd099b 100644
--- a/dependencies.gradle.kts
+++ b/dependencies.gradle.kts
@@ -159,6 +159,9 @@ dependencyResolutionManagement {
// Can"t use the newest version because it hits some weird NoClassDefFoundException
library("jknack-handlebars", "com.github.jknack:handlebars:4.0.7")
+ // Signal-FOSS
+ library("osmdroid", "org.osmdroid:osmdroid-android:6.1.18")
+
// Mp4Parser
library("mp4parser-isoparser", "org.mp4parser", "isoparser").versionRef("mp4parser")
library("mp4parser-streaming", "org.mp4parser", "streaming").versionRef("mp4parser")
diff --git a/donations/lib/build.gradle.kts b/donations/lib/build.gradle.kts
index bf0a70f9cca..ea73680ac29 100644
--- a/donations/lib/build.gradle.kts
+++ b/donations/lib/build.gradle.kts
@@ -5,6 +5,18 @@ plugins {
android {
namespace = "org.signal.donations"
+
+ flavorDimensions += listOf("gms")
+ productFlavors {
+ create("gms") {
+ dimension = "gms"
+ isDefault = true
+ }
+
+ create("foss") {
+ dimension = "gms"
+ }
+ }
}
dependencies {
@@ -18,6 +30,7 @@ dependencies {
exclude(group = "com.google.protobuf", module = "protobuf-java")
}
- api(libs.google.play.services.wallet)
+ "gmsApi"(libs.google.play.services.wallet)
+ "fossApi"(project(":libfakegms"))
api(libs.square.okhttp3)
}
diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml
index 4fa3628980a..fdbea0ecdfa 100644
--- a/gradle/verification-metadata.xml
+++ b/gradle/verification-metadata.xml
@@ -20,6 +20,51 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -8861,3 +8906,4 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
+
diff --git a/libfakegms/build.gradle.kts b/libfakegms/build.gradle.kts
new file mode 100644
index 00000000000..1e0cc7f76fe
--- /dev/null
+++ b/libfakegms/build.gradle.kts
@@ -0,0 +1,14 @@
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+plugins {
+ id("signal-library")
+}
+
+android {
+ namespace = "com.google.android.gms"
+}
+
+dependencies {
+ implementation(libs.androidx.preference)
+ implementation(libs.osmdroid)
+}
diff --git a/libfakegms/src/main/AndroidManifest.xml b/libfakegms/src/main/AndroidManifest.xml
new file mode 100644
index 00000000000..b2d3ea12352
--- /dev/null
+++ b/libfakegms/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/libfakegms/src/main/java/COPYRIGHT b/libfakegms/src/main/java/COPYRIGHT
new file mode 100644
index 00000000000..b0c05afae6f
--- /dev/null
+++ b/libfakegms/src/main/java/COPYRIGHT
@@ -0,0 +1,5 @@
+Licensed under GNU GENERAL PUBLIC LICENSE 3.0
+
+Files under com/google/android (c) 2020 Angus Turnbull https://www.twinhelix.com/
+Files com/google/android/gms/maps/{GoogleMap.java,MapView.java,SupportMapFragment.java} (c) Fumiaki Yoshimatsu https://github.com/fumiakiy/Signal-Android/tree/fumiakiy/share-location-osm
+Files under com/google/firebase (c) Oscar Mira / valldrac https://github.com/mollyim/mollyim-android/tree/master/libfakegms/src/main/java/com/google/firebase
diff --git a/libfakegms/src/main/java/com/google/android/gms/auth/api/phone/SmsRetriever.java b/libfakegms/src/main/java/com/google/android/gms/auth/api/phone/SmsRetriever.java
new file mode 100644
index 00000000000..7c2ac34b6d7
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/auth/api/phone/SmsRetriever.java
@@ -0,0 +1,13 @@
+package com.google.android.gms.auth.api.phone;
+
+import android.content.Context;
+
+public final class SmsRetriever {
+ public static final String EXTRA_SMS_MESSAGE = "com.google.android.gms.auth.api.phone.EXTRA_SMS_MESSAGE";
+ public static final String EXTRA_STATUS = "com.google.android.gms.auth.api.phone.EXTRA_STATUS";
+ public static final String SMS_RETRIEVED_ACTION = "com.google.android.gms.auth.api.phone.SMS_RETRIEVED";
+
+ public static SmsRetrieverClient getClient(Context context) {
+ return new SmsRetrieverClient();
+ }
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/auth/api/phone/SmsRetrieverClient.java b/libfakegms/src/main/java/com/google/android/gms/auth/api/phone/SmsRetrieverClient.java
new file mode 100644
index 00000000000..6b876dc3d7c
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/auth/api/phone/SmsRetrieverClient.java
@@ -0,0 +1,9 @@
+package com.google.android.gms.auth.api.phone;
+
+import com.google.android.gms.tasks.Task;
+
+public final class SmsRetrieverClient {
+ public Task startSmsRetriever() {
+ return new Task();
+ }
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/common/ConnectionResult.java b/libfakegms/src/main/java/com/google/android/gms/common/ConnectionResult.java
new file mode 100644
index 00000000000..45732e1d38e
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/common/ConnectionResult.java
@@ -0,0 +1,11 @@
+package com.google.android.gms.common;
+
+public class ConnectionResult {
+ public static final int SUCCESS = 0;
+ public static final int SERVICE_MISSING = 1;
+ public static final int SERVICE_VERSION_UPDATE_REQUIRED = 2;
+ public static final int SERVICE_DISABLED = 3;
+ public static final int SERVICE_INVALID = 9;
+ public static final int API_UNAVAILABLE = 16;
+ public static final int SERVICE_MISSING_PERMISSION = 19;
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/common/GoogleApiAvailability.java b/libfakegms/src/main/java/com/google/android/gms/common/GoogleApiAvailability.java
new file mode 100644
index 00000000000..e809edc4946
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/common/GoogleApiAvailability.java
@@ -0,0 +1,19 @@
+package com.google.android.gms.common;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.Context;
+
+public class GoogleApiAvailability {
+ public static GoogleApiAvailability getInstance() {
+ return new GoogleApiAvailability();
+ }
+
+ public int isGooglePlayServicesAvailable(Context context) {
+ return ConnectionResult.SERVICE_MISSING;
+ }
+
+ public Dialog getErrorDialog(Activity activity, int errorCode, int requestCode) {
+ return null;
+ }
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/common/api/ApiException.java b/libfakegms/src/main/java/com/google/android/gms/common/api/ApiException.java
new file mode 100644
index 00000000000..3a2340f0bad
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/common/api/ApiException.java
@@ -0,0 +1,4 @@
+package com.google.android.gms.common.api;
+
+public class ApiException extends Exception {
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/common/api/CommonStatusCodes.java b/libfakegms/src/main/java/com/google/android/gms/common/api/CommonStatusCodes.java
new file mode 100644
index 00000000000..a0cd37c7960
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/common/api/CommonStatusCodes.java
@@ -0,0 +1,7 @@
+package com.google.android.gms.common.api;
+
+public class CommonStatusCodes {
+ public static final int ERROR = 12;
+ public static final int SUCCESS = 0;
+ public static final int TIMEOUT = 15;
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/common/api/Status.java b/libfakegms/src/main/java/com/google/android/gms/common/api/Status.java
new file mode 100644
index 00000000000..5dc3aedd61e
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/common/api/Status.java
@@ -0,0 +1,16 @@
+package com.google.android.gms.common.api;
+
+public final class Status {
+ public Status(int statusCode) {
+ }
+
+ public int getStatusCode() {
+ return CommonStatusCodes.ERROR;
+ }
+
+ public String getStatusMessage() {
+ return new String();
+ }
+
+ public static final int RESULT_SUCCESS = 0;
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/maps/CameraUpdate.java b/libfakegms/src/main/java/com/google/android/gms/maps/CameraUpdate.java
new file mode 100644
index 00000000000..e00a50b987c
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/maps/CameraUpdate.java
@@ -0,0 +1,13 @@
+package com.google.android.gms.maps;
+
+import com.google.android.gms.maps.model.LatLng;
+
+public final class CameraUpdate {
+ public final LatLng latLng;
+ public final float zoom;
+
+ public CameraUpdate(LatLng latLng, float zoom) {
+ this.latLng = latLng;
+ this.zoom = zoom;
+ }
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/maps/CameraUpdateFactory.java b/libfakegms/src/main/java/com/google/android/gms/maps/CameraUpdateFactory.java
new file mode 100644
index 00000000000..854da8ac5f0
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/maps/CameraUpdateFactory.java
@@ -0,0 +1,9 @@
+package com.google.android.gms.maps;
+
+import com.google.android.gms.maps.model.LatLng;
+
+public final class CameraUpdateFactory {
+ public static CameraUpdate newLatLngZoom(LatLng latLng, float zoom) {
+ return new CameraUpdate(latLng, zoom);
+ }
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/maps/GoogleMap.java b/libfakegms/src/main/java/com/google/android/gms/maps/GoogleMap.java
new file mode 100644
index 00000000000..72639b963c7
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/maps/GoogleMap.java
@@ -0,0 +1,140 @@
+package com.google.android.gms.maps;
+
+import android.graphics.Bitmap;
+
+import com.google.android.gms.maps.model.CameraPosition;
+import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.MapStyleOptions;
+import com.google.android.gms.maps.model.Marker;
+import com.google.android.gms.maps.model.MarkerOptions;
+
+import org.osmdroid.api.IGeoPoint;
+import org.osmdroid.events.MapListener;
+import org.osmdroid.events.ScrollEvent;
+import org.osmdroid.events.ZoomEvent;
+
+public class GoogleMap {
+ public static final int MAP_TYPE_NONE = 0;
+ public static final int MAP_TYPE_NORMAL = 1;
+ public static final int MAP_TYPE_SATELLITE = 2;
+ public static final int MAP_TYPE_TERRAIN = 3;
+ public static final int MAP_TYPE_HYBRID = 4;
+
+ private final MapView mapView;
+ private final UiSettings uiSettings = new UiSettings();
+ private final MapListener mapListener = new MapListener() {
+
+ private boolean moving = false;
+
+ private final Runnable idleDetector = () -> {
+ moving = false;
+ onCameraIdle();
+ };
+
+ @Override
+ public boolean onScroll(ScrollEvent event) {
+ if (moving) return true;
+
+ onCameraMoveStarted();
+ moving = true;
+ mapView.getHandler().removeCallbacks(idleDetector);
+ mapView.getHandler().postDelayed(idleDetector, 1000);
+
+ return true;
+ }
+
+ @Override
+ public boolean onZoom(ZoomEvent event) {
+ return false;
+ }
+ };
+
+ private CameraPosition cameraPosition;
+ private OnCameraIdleListener onCameraIdleListener;
+ private OnCameraMoveStartedListener onCameraMoveStartedListener;
+
+ public GoogleMap(MapView mapView) {
+ this.mapView = mapView;
+ this.mapView.addMapListener(mapListener);
+ }
+
+ public void setOnCameraMoveStartedListener(OnCameraMoveStartedListener onCameraMoveStartedListener) {
+ this.onCameraMoveStartedListener = onCameraMoveStartedListener;
+ }
+
+ public void setOnCameraIdleListener(OnCameraIdleListener onCameraIdleListener) {
+ this.onCameraIdleListener = onCameraIdleListener;
+ }
+
+ public CameraPosition getCameraPosition() {
+ return cameraPosition;
+ }
+
+ public void moveCamera(CameraUpdate update) {
+ // Zoom in a little bit because OSM Droid's zoom level is slightly wider than Google Maps'
+ float zoom = update.zoom + 2.0f;
+ mapView.setMapPosition(new CameraPosition(update.latLng, zoom));
+ }
+
+ public Marker addMarker(MarkerOptions options) {
+ mapView.addMarker(options);
+ return new Marker();
+ }
+
+ public void setMyLocationEnabled(boolean myLocationEnabled) {
+ mapView.setMyLocationEnabled(myLocationEnabled);
+ }
+
+ public void setBuildingsEnabled(boolean isBuildingsEnabled) { }
+
+ public boolean setMapStyle(MapStyleOptions style) {
+ return false;
+ }
+
+ public void setMapType(int type) { }
+
+ public UiSettings getUiSettings() {
+ return uiSettings;
+ }
+
+ public void setOnMapLoadedCallback (OnMapLoadedCallback callback) {
+ mapView.setOnMapLoadedCallback(callback);
+ }
+
+ public void snapshot(SnapshotReadyCallback callback) {
+ Bitmap bitmap = mapView.snapshot();
+ callback.onSnapshotReady(bitmap);
+ }
+
+ private void onCameraIdle() {
+ if (onCameraIdleListener != null) {
+ onCameraIdleListener.onCameraIdle();
+ }
+ }
+
+ private void onCameraMoveStarted() {
+ IGeoPoint geoPoint = mapView.getMapCenter();
+ LatLng center = new LatLng(geoPoint.getLatitude(), geoPoint.getLongitude());
+ cameraPosition = new CameraPosition(center, (float) mapView.getZoomLevelDouble());
+
+ if (onCameraMoveStartedListener != null) {
+ onCameraMoveStartedListener.onCameraMoveStarted(0);
+ }
+ }
+
+ public interface OnCameraMoveStartedListener {
+ void onCameraMoveStarted(int reason);
+ }
+
+ public interface OnCameraIdleListener {
+ void onCameraIdle();
+ }
+
+ public interface OnMapLoadedCallback {
+ void onMapLoaded();
+ }
+
+ public interface SnapshotReadyCallback {
+ void onSnapshotReady(Bitmap snapshot);
+ }
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/maps/MapView.java b/libfakegms/src/main/java/com/google/android/gms/maps/MapView.java
new file mode 100644
index 00000000000..52cf4e68f62
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/maps/MapView.java
@@ -0,0 +1,158 @@
+package com.google.android.gms.maps;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.util.AttributeSet;
+
+import androidx.core.content.res.ResourcesCompat;
+import androidx.preference.PreferenceManager;
+
+import com.google.android.gms.maps.GoogleMap.OnMapLoadedCallback;
+import com.google.android.gms.maps.model.CameraPosition;
+import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.MarkerOptions;
+
+import org.osmdroid.api.IMapController;
+import org.osmdroid.config.Configuration;
+import org.osmdroid.tileprovider.TileStates;
+import org.osmdroid.util.GeoPoint;
+import org.osmdroid.views.CustomZoomButtonsDisplay;
+import org.osmdroid.views.overlay.Marker;
+
+import org.osmdroid.views.overlay.mylocation.MyLocationNewOverlay;
+import com.google.android.gms.R;
+
+public class MapView extends org.osmdroid.views.MapView {
+ private Marker marker;
+ private boolean isMyLocationEnabled = false;
+ private MyLocationNewOverlay myLocationNewOverlay;
+ private OnMapLoadedCallback onMapLoadedCallback;
+
+ public MapView(Context context) {
+ super(context);
+ }
+
+ public MapView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public MapView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs);
+ }
+
+ public void getMapAsync(OnMapReadyCallback callback) {
+ setDefaultConfiguration(getContext());
+
+ GoogleMap googleMap = new GoogleMap(this);
+ callback.onMapReady(googleMap);
+ }
+
+ private void setDefaultConfiguration(Context context) {
+ String userAgent = String.format("Signal-FOSS/7");
+ Configuration.getInstance().load(context, PreferenceManager.getDefaultSharedPreferences(context));
+ Configuration.getInstance().setUserAgentValue(userAgent);
+
+ getZoomController().getDisplay().setPositions(
+ false,
+ CustomZoomButtonsDisplay.HorizontalPosition.RIGHT,
+ CustomZoomButtonsDisplay.VerticalPosition.TOP);
+ setMultiTouchControls(true);
+ }
+
+ void addMarker(MarkerOptions markerOptions) {
+ removeExistingMarker();
+
+ marker = new Marker(this);
+ marker.setPosition(toPoint(markerOptions.getPosition()));
+ Drawable icon = ResourcesCompat.getDrawable(
+ getContext().getResources(),
+ R.drawable.ic_map_marker,
+ getContext().getTheme());
+ marker.setIcon(icon);
+ getOverlays().add(marker);
+ }
+
+ private void removeExistingMarker() {
+ if (marker == null) return;
+ getOverlays().remove(marker);
+ marker = null;
+ }
+
+ void setMapPosition(CameraPosition position) {
+ IMapController mapController = getController();
+ mapController.setCenter(toPoint(position.target));
+ mapController.setZoom(position.zoom);
+ waitMapRender();
+ }
+
+ Bitmap snapshot() {
+ Bitmap bitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ layout(getLeft(), getTop(), getRight(), getBottom());
+ draw(canvas);
+ return bitmap;
+ }
+
+ private void waitMapRender() {
+ postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ TileStates tileStates = getOverlayManager().getTilesOverlay().getTileStates();
+ if (tileStates.getTotal() > 0 && (tileStates.getTotal() == tileStates.getUpToDate())) {
+ if (onMapLoadedCallback != null) onMapLoadedCallback.onMapLoaded();
+ } else {
+ // We are not done yet. wait for a few cycles and check again
+ postDelayed(this, 72);
+ }
+ }
+ }, 72);
+ }
+
+ void setOnMapLoadedCallback(OnMapLoadedCallback onMapLoadedCallback) {
+ this.onMapLoadedCallback = onMapLoadedCallback;
+ }
+
+ void setMyLocationEnabled(boolean isMyLocationEnabled) {
+ // TODO this code does not add the "jump to my location" button on the map atm.
+ this.isMyLocationEnabled = isMyLocationEnabled;
+ if (isMyLocationEnabled) {
+ if (myLocationNewOverlay == null) {
+ myLocationNewOverlay = new MyLocationNewOverlay(this);
+ myLocationNewOverlay.enableMyLocation();
+ }
+ getOverlays().add(myLocationNewOverlay);
+ } else if (myLocationNewOverlay != null) {
+ getOverlays().remove(myLocationNewOverlay);
+ myLocationNewOverlay.disableMyLocation();
+ }
+ }
+
+ public final void onCreate(Bundle savedInstanceState) { }
+
+ public final void onStart() { }
+
+ public final void onResume() {
+ super.onResume();
+ if (myLocationNewOverlay != null && isMyLocationEnabled) {
+ myLocationNewOverlay.enableMyLocation();
+ }
+ }
+
+ public final void onPause() {
+ super.onPause();
+ if (myLocationNewOverlay != null) {
+ myLocationNewOverlay.disableMyLocation();
+ }
+ }
+
+ public final void onStop() { }
+
+ public final void onDestroy() { }
+
+ private GeoPoint toPoint(LatLng latLng) {
+ return new GeoPoint(latLng.latitude, latLng.longitude);
+ }
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/maps/OnMapReadyCallback.java b/libfakegms/src/main/java/com/google/android/gms/maps/OnMapReadyCallback.java
new file mode 100644
index 00000000000..5c6fba29bcd
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/maps/OnMapReadyCallback.java
@@ -0,0 +1,5 @@
+package com.google.android.gms.maps;
+
+public interface OnMapReadyCallback {
+ public void onMapReady(GoogleMap googleMap);
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/maps/SupportMapFragment.java b/libfakegms/src/main/java/com/google/android/gms/maps/SupportMapFragment.java
new file mode 100644
index 00000000000..1f3e9bf2c8a
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/maps/SupportMapFragment.java
@@ -0,0 +1,60 @@
+package com.google.android.gms.maps;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+
+public class SupportMapFragment extends Fragment {
+ private MapView mapView;
+
+ public void getMapAsync(OnMapReadyCallback callback) {
+ if (mapView == null) return;
+ mapView.getMapAsync(callback);
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState)
+ {
+ mapView = new MapView(inflater.getContext());
+ mapView.onCreate(savedInstanceState);
+ return mapView;
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ mapView.onStart();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mapView.onResume();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mapView.onPause();
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ mapView.onStop();
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ mapView.onDestroy();
+ mapView = null;
+ }
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/maps/UiSettings.java b/libfakegms/src/main/java/com/google/android/gms/maps/UiSettings.java
new file mode 100644
index 00000000000..14f976544d2
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/maps/UiSettings.java
@@ -0,0 +1,6 @@
+package com.google.android.gms.maps;
+
+public final class UiSettings {
+ public void setAllGesturesEnabled(boolean enabled) {
+ }
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/maps/model/CameraPosition.java b/libfakegms/src/main/java/com/google/android/gms/maps/model/CameraPosition.java
new file mode 100644
index 00000000000..a9973ff1f68
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/maps/model/CameraPosition.java
@@ -0,0 +1,12 @@
+package com.google.android.gms.maps.model;
+
+public final class CameraPosition {
+ public LatLng target;
+ public float zoom;
+
+ public CameraPosition(LatLng target, float zoom) {
+ this.target = target;
+ this.zoom = zoom;
+ }
+}
+
diff --git a/libfakegms/src/main/java/com/google/android/gms/maps/model/LatLng.java b/libfakegms/src/main/java/com/google/android/gms/maps/model/LatLng.java
new file mode 100644
index 00000000000..d21a1e4ac2e
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/maps/model/LatLng.java
@@ -0,0 +1,11 @@
+package com.google.android.gms.maps.model;
+
+public final class LatLng {
+ public LatLng(double latitude, double longitude) {
+ this.latitude = latitude;
+ this.longitude = longitude;
+ }
+
+ public double latitude = 0;
+ public double longitude = 0;
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/maps/model/MapStyleOptions.java b/libfakegms/src/main/java/com/google/android/gms/maps/model/MapStyleOptions.java
new file mode 100644
index 00000000000..a54defdb34a
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/maps/model/MapStyleOptions.java
@@ -0,0 +1,9 @@
+package com.google.android.gms.maps.model;
+
+import android.content.Context;
+
+public final class MapStyleOptions {
+ public static MapStyleOptions loadRawResourceStyle(Context clientContext, int resourceId) {
+ return new MapStyleOptions();
+ }
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/maps/model/Marker.java b/libfakegms/src/main/java/com/google/android/gms/maps/model/Marker.java
new file mode 100644
index 00000000000..d1c22a749b1
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/maps/model/Marker.java
@@ -0,0 +1,4 @@
+package com.google.android.gms.maps.model;
+
+public final class Marker {
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/maps/model/MarkerOptions.java b/libfakegms/src/main/java/com/google/android/gms/maps/model/MarkerOptions.java
new file mode 100644
index 00000000000..4bd6d0ca45a
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/maps/model/MarkerOptions.java
@@ -0,0 +1,14 @@
+package com.google.android.gms.maps.model;
+
+public final class MarkerOptions {
+ private LatLng latLng;
+
+ public MarkerOptions position(LatLng latLng) {
+ this.latLng = latLng;
+ return this;
+ }
+
+ public LatLng getPosition() {
+ return this.latLng;
+ }
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/security/ProviderInstaller.java b/libfakegms/src/main/java/com/google/android/gms/security/ProviderInstaller.java
new file mode 100644
index 00000000000..0119fef0fef
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/security/ProviderInstaller.java
@@ -0,0 +1,8 @@
+package com.google.android.gms.security;
+
+import android.content.Context;
+
+public class ProviderInstaller {
+ public static void installIfNeeded(Context context) {
+ }
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/tasks/OnCanceledListener.java b/libfakegms/src/main/java/com/google/android/gms/tasks/OnCanceledListener.java
new file mode 100644
index 00000000000..f2919ebad95
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/tasks/OnCanceledListener.java
@@ -0,0 +1,5 @@
+package com.google.android.gms.tasks;
+
+public interface OnCanceledListener {
+ void onCanceled();
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/tasks/OnCompleteListener.java b/libfakegms/src/main/java/com/google/android/gms/tasks/OnCompleteListener.java
new file mode 100644
index 00000000000..618c09b8e5e
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/tasks/OnCompleteListener.java
@@ -0,0 +1,5 @@
+package com.google.android.gms.tasks;
+
+public interface OnCompleteListener {
+ void onComplete(Task result);
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/tasks/OnFailureListener.java b/libfakegms/src/main/java/com/google/android/gms/tasks/OnFailureListener.java
new file mode 100644
index 00000000000..76e24082208
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/tasks/OnFailureListener.java
@@ -0,0 +1,5 @@
+package com.google.android.gms.tasks;
+
+public interface OnFailureListener {
+ void onFailure(Exception e);
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/tasks/OnSuccessListener.java b/libfakegms/src/main/java/com/google/android/gms/tasks/OnSuccessListener.java
new file mode 100644
index 00000000000..b0ba4409b80
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/tasks/OnSuccessListener.java
@@ -0,0 +1,5 @@
+package com.google.android.gms.tasks;
+
+public interface OnSuccessListener {
+ void onSuccess(TResult result);
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/tasks/Task.java b/libfakegms/src/main/java/com/google/android/gms/tasks/Task.java
new file mode 100644
index 00000000000..3383dcc7cc6
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/tasks/Task.java
@@ -0,0 +1,42 @@
+package com.google.android.gms.tasks;
+
+public class Task {
+ public Task addOnCanceledListener(OnCanceledListener listener) {
+ listener.onCanceled();
+ return this;
+ }
+
+ public Task addOnCompleteListener(OnCompleteListener listener) {
+ listener.onComplete(this);
+ return this;
+ }
+
+ public Task addOnFailureListener(OnFailureListener listener) {
+ listener.onFailure(getException());
+ return this;
+ }
+
+ public Task addOnSuccessListener(OnSuccessListener listener) {
+ return this;
+ }
+
+ public TResult getResult() {
+ return null;
+ }
+
+ public TResult getResult(Class exceptionType) {
+ return null;
+ }
+
+ public boolean isSuccessful() {
+ return false;
+ }
+
+ public Exception getException() {
+ return new UnsupportedOperationException();
+ }
+
+ public void await() {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/tasks/Tasks.java b/libfakegms/src/main/java/com/google/android/gms/tasks/Tasks.java
new file mode 100644
index 00000000000..fd5eaf611d4
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/tasks/Tasks.java
@@ -0,0 +1,9 @@
+package com.google.android.gms.tasks;
+
+import java.util.concurrent.ExecutionException;
+
+public final class Tasks {
+ public static TResult await(Task task) throws ExecutionException, InterruptedException {
+ return task.getResult();
+ }
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/wallet/AutoResolveHelper.java b/libfakegms/src/main/java/com/google/android/gms/wallet/AutoResolveHelper.java
new file mode 100644
index 00000000000..8e4f5b42dbf
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/wallet/AutoResolveHelper.java
@@ -0,0 +1,18 @@
+package com.google.android.gms.wallet;
+
+import android.app.Activity;
+import android.content.Intent;
+import com.google.android.gms.common.api.CommonStatusCodes;
+import com.google.android.gms.common.api.Status;
+import com.google.android.gms.tasks.Task;
+
+public class AutoResolveHelper {
+ public static void resolveTask(Task task, Activity activity, int requestCode) {
+ }
+
+ public static Status getStatusFromIntent (Intent data) {
+ return new Status(CommonStatusCodes.ERROR);
+ }
+
+ public static final int RESULT_ERROR = 1;
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/wallet/IsReadyToPayRequest.java b/libfakegms/src/main/java/com/google/android/gms/wallet/IsReadyToPayRequest.java
new file mode 100644
index 00000000000..a4960f395b4
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/wallet/IsReadyToPayRequest.java
@@ -0,0 +1,7 @@
+package com.google.android.gms.wallet;
+
+public final class IsReadyToPayRequest {
+ public static IsReadyToPayRequest fromJson(String isReadyToPayRequestJson) {
+ return new IsReadyToPayRequest();
+ }
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/wallet/PaymentData.java b/libfakegms/src/main/java/com/google/android/gms/wallet/PaymentData.java
new file mode 100644
index 00000000000..b7943eb84ae
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/wallet/PaymentData.java
@@ -0,0 +1,13 @@
+package com.google.android.gms.wallet;
+
+import android.content.Intent;
+
+public final class PaymentData {
+ public static PaymentData getFromIntent(Intent intent) {
+ return null;
+ }
+
+ public String toJson() {
+ return "";
+ }
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/wallet/PaymentDataRequest.java b/libfakegms/src/main/java/com/google/android/gms/wallet/PaymentDataRequest.java
new file mode 100644
index 00000000000..3eb3a16f0e3
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/wallet/PaymentDataRequest.java
@@ -0,0 +1,7 @@
+package com.google.android.gms.wallet;
+
+public final class PaymentDataRequest {
+ public static PaymentDataRequest fromJson(String paymentDataRequestJson) {
+ return new PaymentDataRequest();
+ }
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/wallet/PaymentsClient.java b/libfakegms/src/main/java/com/google/android/gms/wallet/PaymentsClient.java
new file mode 100644
index 00000000000..7c2259b785c
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/wallet/PaymentsClient.java
@@ -0,0 +1,13 @@
+package com.google.android.gms.wallet;
+
+import com.google.android.gms.tasks.Task;
+
+public class PaymentsClient {
+ public Task isReadyToPay(IsReadyToPayRequest request) {
+ return new Task();
+ }
+
+ public Task loadPaymentData(PaymentDataRequest request) {
+ return new Task();
+ }
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/wallet/Wallet.java b/libfakegms/src/main/java/com/google/android/gms/wallet/Wallet.java
new file mode 100644
index 00000000000..dfdcc83cb85
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/wallet/Wallet.java
@@ -0,0 +1,22 @@
+package com.google.android.gms.wallet;
+
+import android.app.Activity;
+import android.content.Context;
+
+public final class Wallet {
+ public static final class WalletOptions {
+ public static final class Builder {
+ public Builder setEnvironment(int environment) {
+ return this;
+ }
+
+ public WalletOptions build() {
+ return new WalletOptions();
+ }
+ }
+ }
+
+ public static PaymentsClient getPaymentsClient(Context context, Wallet.WalletOptions options) {
+ return new PaymentsClient();
+ }
+}
diff --git a/libfakegms/src/main/java/com/google/android/gms/wallet/WalletConstants.java b/libfakegms/src/main/java/com/google/android/gms/wallet/WalletConstants.java
new file mode 100644
index 00000000000..a330f2c153b
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/android/gms/wallet/WalletConstants.java
@@ -0,0 +1,6 @@
+package com.google.android.gms.wallet;
+
+public final class WalletConstants {
+ public static final int ENVIRONMENT_PRODUCTION = 1;
+ public static final int ENVIRONMENT_TEST = 3;
+}
diff --git a/libfakegms/src/main/java/com/google/firebase/FirebaseApp.java b/libfakegms/src/main/java/com/google/firebase/FirebaseApp.java
new file mode 100644
index 00000000000..d4801ac8a70
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/firebase/FirebaseApp.java
@@ -0,0 +1,9 @@
+package com.google.firebase;
+
+import android.content.Context;
+
+public class FirebaseApp extends Object {
+ public static FirebaseApp initializeApp(Context context) {
+ return new FirebaseApp();
+ }
+}
diff --git a/libfakegms/src/main/java/com/google/firebase/iid/FirebaseInstanceId.java b/libfakegms/src/main/java/com/google/firebase/iid/FirebaseInstanceId.java
new file mode 100644
index 00000000000..f2581493517
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/firebase/iid/FirebaseInstanceId.java
@@ -0,0 +1,18 @@
+package com.google.firebase.iid;
+
+import com.google.android.gms.tasks.Task;
+
+public class FirebaseInstanceId {
+ private static final FirebaseInstanceId INSTANCE = new FirebaseInstanceId();
+
+ public static FirebaseInstanceId getInstance() {
+ return INSTANCE;
+ }
+
+ public void deleteInstanceId() {
+ }
+
+ public Task getInstanceId() {
+ return new Task();
+ }
+}
diff --git a/libfakegms/src/main/java/com/google/firebase/installations/FirebaseInstallations.java b/libfakegms/src/main/java/com/google/firebase/installations/FirebaseInstallations.java
new file mode 100644
index 00000000000..974dbd096cd
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/firebase/installations/FirebaseInstallations.java
@@ -0,0 +1,15 @@
+package com.google.firebase.installations;
+
+import com.google.android.gms.tasks.Task;
+
+public class FirebaseInstallations {
+ private static final FirebaseInstallations INSTANCE = new FirebaseInstallations();
+
+ public static FirebaseInstallations getInstance() {
+ return INSTANCE;
+ }
+
+ public Task delete() {
+ return new Task<>();
+ }
+}
diff --git a/libfakegms/src/main/java/com/google/firebase/messaging/FirebaseMessaging.java b/libfakegms/src/main/java/com/google/firebase/messaging/FirebaseMessaging.java
new file mode 100644
index 00000000000..eb90f41395b
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/firebase/messaging/FirebaseMessaging.java
@@ -0,0 +1,15 @@
+package com.google.firebase.messaging;
+
+import com.google.android.gms.tasks.Task;
+
+public class FirebaseMessaging {
+ private static final FirebaseMessaging INSTANCE = new FirebaseMessaging();
+
+ public static FirebaseMessaging getInstance() {
+ return INSTANCE;
+ }
+
+ public Task getToken() {
+ return new Task<>();
+ }
+}
diff --git a/libfakegms/src/main/java/com/google/firebase/messaging/FirebaseMessagingService.java b/libfakegms/src/main/java/com/google/firebase/messaging/FirebaseMessagingService.java
new file mode 100644
index 00000000000..f3fe786b8bf
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/firebase/messaging/FirebaseMessagingService.java
@@ -0,0 +1,22 @@
+package com.google.firebase.messaging;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+public abstract class FirebaseMessagingService extends Service {
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ public abstract void onDeletedMessages();
+
+ public abstract void onMessageReceived(RemoteMessage remoteMessage);
+
+ public abstract void onMessageSent(String s);
+
+ public abstract void onNewToken(String token);
+
+ public abstract void onSendError(String s, Exception e);
+}
diff --git a/libfakegms/src/main/java/com/google/firebase/messaging/RemoteMessage.java b/libfakegms/src/main/java/com/google/firebase/messaging/RemoteMessage.java
new file mode 100644
index 00000000000..328860a85a1
--- /dev/null
+++ b/libfakegms/src/main/java/com/google/firebase/messaging/RemoteMessage.java
@@ -0,0 +1,31 @@
+package com.google.firebase.messaging;
+
+public class RemoteMessage {
+ public Data getData() {
+ return new Data();
+ }
+
+ public String getMessageId() {
+ return "";
+ }
+
+ public int getOriginalPriority() {
+ return 0;
+ }
+
+ public int getPriority() {
+ return 0;
+ }
+
+ public long getSentTime() {
+ return 0;
+ }
+
+ public static class Data {
+ public String get(String challenge) {
+ return null;
+ }
+ }
+
+ public static int PRIORITY_HIGH = 1;
+}
diff --git a/libfakegms/src/main/java/kotlinx/coroutines/tasks/await.java b/libfakegms/src/main/java/kotlinx/coroutines/tasks/await.java
new file mode 100644
index 00000000000..de5e61c6b9d
--- /dev/null
+++ b/libfakegms/src/main/java/kotlinx/coroutines/tasks/await.java
@@ -0,0 +1,4 @@
+package kotlinx.coroutines.tasks;
+
+public abstract class await {
+}
diff --git a/libfakegms/src/main/res/drawable/ic_map_marker.xml b/libfakegms/src/main/res/drawable/ic_map_marker.xml
new file mode 100644
index 00000000000..f1b770e6950
--- /dev/null
+++ b/libfakegms/src/main/res/drawable/ic_map_marker.xml
@@ -0,0 +1,10 @@
+
+
+
+
diff --git a/libfakegms/src/main/res/layout/donate_with_googlepay_button.xml b/libfakegms/src/main/res/layout/donate_with_googlepay_button.xml
new file mode 100644
index 00000000000..4f6c36c81ed
--- /dev/null
+++ b/libfakegms/src/main/res/layout/donate_with_googlepay_button.xml
@@ -0,0 +1,6 @@
+
+
+
diff --git a/libfakegms/src/main/res/values/version.xml b/libfakegms/src/main/res/values/version.xml
new file mode 100644
index 00000000000..30f5451b67b
--- /dev/null
+++ b/libfakegms/src/main/res/values/version.xml
@@ -0,0 +1,4 @@
+
+
+ 1
+
diff --git a/settings.gradle.kts b/settings.gradle.kts
index a4d05b2059f..5e7c32f4bd3 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -30,6 +30,7 @@ dependencyResolutionManagement {
}
include(":app")
+include(":libfakegms")
include(":libsignal-service")
include(":lintchecks")
include(":paging")