From 119c36691d3fd3fe89f32eb928de7a426fd47c52 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Fri, 8 Nov 2024 01:22:11 +0100 Subject: [PATCH 1/2] Make Geolocation plugin work if Google Play Services are not enabled or missing --- .../plugins/geolocation/Geolocation.java | 178 +++++++++++++----- 1 file changed, 131 insertions(+), 47 deletions(-) diff --git a/geolocation/android/src/main/java/com/capacitorjs/plugins/geolocation/Geolocation.java b/geolocation/android/src/main/java/com/capacitorjs/plugins/geolocation/Geolocation.java index 41b8af269..516d22a55 100644 --- a/geolocation/android/src/main/java/com/capacitorjs/plugins/geolocation/Geolocation.java +++ b/geolocation/android/src/main/java/com/capacitorjs/plugins/geolocation/Geolocation.java @@ -1,10 +1,15 @@ -package com.capacitorjs.plugins.geolocation; +package org.mapcomplete; import android.content.Context; import android.location.Location; +import android.location.LocationListener; import android.location.LocationManager; +import android.os.Bundle; import android.os.SystemClock; +import android.util.Log; + import androidx.core.location.LocationManagerCompat; + import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GoogleApiAvailability; import com.google.android.gms.location.FusedLocationProviderClient; @@ -14,6 +19,33 @@ import com.google.android.gms.location.LocationServices; import com.google.android.gms.location.Priority; +class LocationUpdateListener implements LocationListener { + + private final LocationResultCallback callback; + + public LocationUpdateListener(LocationResultCallback callback) { + + this.callback = callback; + } + + @Override + public void onLocationChanged(Location location) { + this.callback.success(location); + } + + @Override + public void onStatusChanged(String provider, int status, Bundle extras) { + } + + @Override + public void onProviderEnabled(String provider) { + } + + @Override + public void onProviderDisabled(String provider) { + } +} + public class Geolocation { private FusedLocationProviderClient fusedLocationClient; @@ -30,68 +62,117 @@ public Boolean isLocationServicesEnabled() { return LocationManagerCompat.isLocationEnabled(lm); } - @SuppressWarnings("MissingPermission") - public void sendLocation(boolean enableHighAccuracy, final LocationResultCallback resultCallback) { - int resultCode = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context); - if (resultCode == ConnectionResult.SUCCESS) { - LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); + private int getPriority(boolean enableHighAccuracy) { + boolean networkEnabled = false; + if (enableHighAccuracy) { + return Priority.PRIORITY_HIGH_ACCURACY; + } + LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); + try { + networkEnabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER); + } catch (Exception ex) { + } + return networkEnabled ? Priority.PRIORITY_BALANCED_POWER_ACCURACY : Priority.PRIORITY_LOW_POWER; + } + + private boolean hasPlayServices() { + return GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS; + } - if (this.isLocationServicesEnabled()) { - boolean networkEnabled = false; + /** + * If the play services are disabled, the location manager will be queryied to indicate what providers are available. + * Typical providers are `passive`, `network`, `fused` and `gps` + * + * This method selects the best appropriate + */ + private String getPreferredProvider(boolean enableHighAccuracy) { + LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); + var providers = lm.getProviders(true); + if(enableHighAccuracy) { + if(providers.contains("gps")){ + return "gps"; + } + if(providers.contains("fused")){ + return "fused"; + } + if(providers.contains("network")){ + return "network"; + } + }else{ + if(providers.contains("network")){ + return "network"; + } + if(providers.contains("fused")){ + return "fused"; + } + if(providers.contains("gps")){ + return "gps"; + } + } + if(providers.contains("passive")){ + return "passive"; + } - try { - networkEnabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER); - } catch (Exception ex) {} + return null; + } + @SuppressWarnings("MissingPermission") + public void sendLocation(boolean enableHighAccuracy, final LocationResultCallback resultCallback) { + if (!this.isLocationServicesEnabled()) { + resultCallback.error("location disabled"); + return; + } - int lowPriority = networkEnabled ? Priority.PRIORITY_BALANCED_POWER_ACCURACY : Priority.PRIORITY_LOW_POWER; - int priority = enableHighAccuracy ? Priority.PRIORITY_HIGH_ACCURACY : lowPriority; + if (hasPlayServices()) { - LocationServices + LocationServices .getFusedLocationProviderClient(context) - .getCurrentLocation(priority, null) + .getCurrentLocation(getPriority(enableHighAccuracy), null) .addOnFailureListener(e -> resultCallback.error(e.getMessage())) .addOnSuccessListener( - location -> { - if (location == null) { - resultCallback.error("location unavailable"); - } else { - resultCallback.success(location); + location -> { + if (location == null) { + resultCallback.error("location unavailable"); + } else { + resultCallback.success(location); + } } - } ); - } else { - resultCallback.error("location disabled"); - } } else { - resultCallback.error("Google Play Services not available"); + LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); + + var provider = getPreferredProvider(enableHighAccuracy); + if (provider == null) { + resultCallback.error("Location unavaible: no providers defined. Note: Google Play Services are not available as well"); + return; + } + lm.requestLocationUpdates(provider, 1000, 10, new LocationUpdateListener(resultCallback)); } + + } @SuppressWarnings("MissingPermission") public void requestLocationUpdates(boolean enableHighAccuracy, int timeout, final LocationResultCallback resultCallback) { - int resultCode = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context); - if (resultCode == ConnectionResult.SUCCESS) { - clearLocationUpdates(); - fusedLocationClient = LocationServices.getFusedLocationProviderClient(context); - LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); - if (this.isLocationServicesEnabled()) { - boolean networkEnabled = false; - try { - networkEnabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER); - } catch (Exception ex) {} + if (!this.isLocationServicesEnabled()) { + resultCallback.error("location disabled"); + return; + } + + LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); - int lowPriority = networkEnabled ? Priority.PRIORITY_BALANCED_POWER_ACCURACY : Priority.PRIORITY_LOW_POWER; - int priority = enableHighAccuracy ? Priority.PRIORITY_HIGH_ACCURACY : lowPriority; + if (hasPlayServices()) { + clearLocationUpdates(); + fusedLocationClient = LocationServices.getFusedLocationProviderClient(context); - LocationRequest locationRequest = new LocationRequest.Builder(10000) + LocationRequest locationRequest = new LocationRequest.Builder(10000) .setMaxUpdateDelayMillis(timeout) .setMinUpdateIntervalMillis(5000) - .setPriority(priority) + .setPriority(getPriority(enableHighAccuracy)) .build(); - locationCallback = + locationCallback = new LocationCallback() { @Override public void onLocationResult(LocationResult locationResult) { @@ -104,12 +185,15 @@ public void onLocationResult(LocationResult locationResult) { } }; - fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, null); - } else { - resultCallback.error("location disabled"); - } + fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, null); } else { - resultCallback.error("Google Play Services not available"); + var provider = getPreferredProvider(enableHighAccuracy); + if (provider == null) { + resultCallback.error("Location unavaible: no providers defined. Note: Google Play Services are not available as well"); + return; + } + lm.requestLocationUpdates(provider, 1000, 10, new LocationUpdateListener(resultCallback)); + } } @@ -130,8 +214,8 @@ public Location getLastLocation(int maximumAge) { long locationAge = SystemClock.elapsedRealtimeNanos() - tmpLoc.getElapsedRealtimeNanos(); long maximumAgeNanoSec = maximumAge * 1000000L; if ( - locationAge <= maximumAgeNanoSec && - (lastLoc == null || lastLoc.getElapsedRealtimeNanos() > tmpLoc.getElapsedRealtimeNanos()) + locationAge <= maximumAgeNanoSec && + (lastLoc == null || lastLoc.getElapsedRealtimeNanos() > tmpLoc.getElapsedRealtimeNanos()) ) { lastLoc = tmpLoc; } From a65451eb564c66c3b0ac79a21709d9d0df2920af Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Fri, 8 Nov 2024 01:24:41 +0100 Subject: [PATCH 2/2] Fix package name --- .../java/com/capacitorjs/plugins/geolocation/Geolocation.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/geolocation/android/src/main/java/com/capacitorjs/plugins/geolocation/Geolocation.java b/geolocation/android/src/main/java/com/capacitorjs/plugins/geolocation/Geolocation.java index 516d22a55..77e670966 100644 --- a/geolocation/android/src/main/java/com/capacitorjs/plugins/geolocation/Geolocation.java +++ b/geolocation/android/src/main/java/com/capacitorjs/plugins/geolocation/Geolocation.java @@ -1,4 +1,4 @@ -package org.mapcomplete; +package com.capacitorjs.plugins.geolocation; import android.content.Context; import android.location.Location; @@ -6,7 +6,6 @@ import android.location.LocationManager; import android.os.Bundle; import android.os.SystemClock; -import android.util.Log; import androidx.core.location.LocationManagerCompat;