Skip to content

Commit

Permalink
Merge pull request #6028 from grzesiek2010/COLLECT-6027
Browse files Browse the repository at this point in the history
Revert "Migrate to FusedLocationProviderClient"
  • Loading branch information
seadowg committed Mar 22, 2024
2 parents 355dbc6 + 56fb334 commit 7ba3c4f
Show file tree
Hide file tree
Showing 6 changed files with 516 additions and 279 deletions.
2 changes: 1 addition & 1 deletion buildSrc/src/main/java/dependencies/Dependencies.kt
Expand Up @@ -21,7 +21,7 @@ object Dependencies {
const val android_material = "com.google.android.material:material:1.9.0"
const val android_flexbox = "com.google.android.flexbox:flexbox:3.0.0"
const val play_services_maps = "com.google.android.gms:play-services-maps:18.2.0"
const val play_services_location = "com.google.android.gms:play-services-location:21.0.1"
const val play_services_location = "com.google.android.gms:play-services-location:20.0.0" // Check if map screens still work when upgrading and location works as expected https://github.com/getodk/collect/issues/6027, especially after moving to FusedLocationProviderClient.
const val play_services_oss_licenses = "com.google.android.gms:play-services-oss-licenses:17.0.1"
const val mapbox_android_sdk = "com.mapbox.maps:android:10.16.1"
const val osmdroid = "org.osmdroid:osmdroid-android:6.1.17"
Expand Down
Expand Up @@ -12,7 +12,7 @@ import org.odk.collect.location.LocationClient.LocationClientListener
*
* @param locationManager The LocationManager to retrieve locations from.
*/
abstract class BaseLocationClient(protected val locationManager: LocationManager?) :
internal abstract class BaseLocationClient(protected val locationManager: LocationManager?) :
LocationClient {

private var listener: LocationClientListener? = null
Expand Down Expand Up @@ -84,7 +84,7 @@ abstract class BaseLocationClient(protected val locationManager: LocationManager
listener = locationClientListener
}

fun getListener(): LocationClientListener? {
protected fun getListener(): LocationClientListener? {
return listener
}
}
@@ -0,0 +1,231 @@
package org.odk.collect.location;

import android.annotation.SuppressLint;
import android.app.Application;
import android.content.Context;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import com.google.android.gms.location.FusedLocationProviderApi;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;

import org.odk.collect.analytics.Analytics;

import timber.log.Timber;

/**
* An implementation of {@link LocationClient} that uses Google Play Services to retrieve the
* User's location.
* <p>
* Should be used whenever there Google Play Services is present. In general, use
* {@link LocationClientProvider} to retrieve a configured {@link LocationClient}.
*/
@SuppressLint("MissingPermission") // Permission checks for location services handled in components that use this class
public class GoogleFusedLocationClient
extends BaseLocationClient
implements ConnectionCallbacks, OnConnectionFailedListener, LocationListener {

/**
* The default requested time between location updates, in milliseconds.
*/
private static final long DEFAULT_UPDATE_INTERVAL = 5000;

/**
* The default maximum rate at which location updates can arrive (other updates will be throttled),
* in milliseconds.
*/
private static final long DEFAULT_FASTEST_UPDATE_INTERVAL = 2500;

/**
* Although FusedLocationProviderApi is deprecated, FusedLocationProviderClient which is
* supposed to replace it doesn't work until Google Play Services 11.6.0, released Nov 2017.
* Some of our users have really slow connections and old versions of Play Services so we should
* wait to switch APIs.
*/
@NonNull
private final FusedLocationProviderApi fusedLocationProviderApi;

@NonNull
private final GoogleApiClient googleApiClient;

@Nullable
private LocationListener locationListener;

private long updateInterval = DEFAULT_UPDATE_INTERVAL;
private long fastestUpdateInterval = DEFAULT_FASTEST_UPDATE_INTERVAL;
private boolean retainMockAccuracy;

/**
* Constructs a new GoogleFusedLocationClient with the provided Context.
* <p>
* This Constructor should be used normally.
*
* @param application The application. Used as the Context for building the GoogleApiClient because
* it doesn't release context.
*/
public GoogleFusedLocationClient(@NonNull Application application) {
this(locationServicesClientForContext(application), LocationServices.FusedLocationApi,
(LocationManager) application.getSystemService(Context.LOCATION_SERVICE));
}

/**
* Constructs a new AndroidLocationClient with the provided GoogleApiClient
* and FusedLocationProviderApi.
* <p>
* This Constructor should only be used for testing.
*
* @param googleApiClient The GoogleApiClient for managing the LocationClient's connection
* to Play Services.
* @param fusedLocationProviderApi The FusedLocationProviderApi for fetching the User's
* location.
*/
public GoogleFusedLocationClient(@NonNull GoogleApiClient googleApiClient,
@NonNull FusedLocationProviderApi fusedLocationProviderApi,
@NonNull LocationManager locationManager) {
super(locationManager);

this.googleApiClient = googleApiClient;
this.fusedLocationProviderApi = fusedLocationProviderApi;
}

// LocationClient:

public void start(LocationClientListener listener) {
setListener(listener);
googleApiClient.registerConnectionCallbacks(this);
googleApiClient.registerConnectionFailedListener(this);

googleApiClient.connect();
}

public void stop() {
stopLocationUpdates();

googleApiClient.unregisterConnectionCallbacks(this);
googleApiClient.unregisterConnectionFailedListener(this);

if (googleApiClient.isConnected()) {
googleApiClient.disconnect();
}

if (getListener() != null) {
getListener().onClientStop();
}
setListener(null);
}

public void requestLocationUpdates(@NonNull LocationListener locationListener) {
if (!isMonitoringLocation() && googleApiClient.isConnected()) {
fusedLocationProviderApi.requestLocationUpdates(googleApiClient, createLocationRequest(), this);
}

this.locationListener = locationListener;
}

public void stopLocationUpdates() {
if (!isMonitoringLocation()) {
return;
}

if (googleApiClient.isConnected()) {
fusedLocationProviderApi.removeLocationUpdates(googleApiClient, locationListener);
}
locationListener = null;
}

@Override
public void setRetainMockAccuracy(boolean retainMockAccuracy) {
this.retainMockAccuracy = retainMockAccuracy;
}

@Override
public Location getLastLocation() {
// We need to block if the Client isn't already connected:
if (!googleApiClient.isConnected()) {
googleApiClient.blockingConnect();
}

return LocationUtils.sanitizeAccuracy(fusedLocationProviderApi.getLastLocation(googleApiClient), retainMockAccuracy);
}

@Override
public boolean isMonitoringLocation() {
return locationListener != null;
}

@Override
public void setUpdateIntervals(long updateInterval, long fastestUpdateInterval) {
Timber.i("GoogleFusedLocationClient setting update intervals: %d, %d", updateInterval, fastestUpdateInterval);

this.updateInterval = updateInterval;
this.fastestUpdateInterval = fastestUpdateInterval;
}

// GoogleFusedLocationClient:

private LocationRequest createLocationRequest() {
LocationRequest locationRequest = new LocationRequest();
locationRequest.setPriority(getPriority().getValue());

locationRequest.setInterval(updateInterval);
locationRequest.setFastestInterval(fastestUpdateInterval);

return locationRequest;
}

// ConnectionCallbacks:

@Override
public void onConnected(@Nullable Bundle bundle) {
if (getListener() != null) {
getListener().onClientStart();
}
}

@Override
public void onConnectionSuspended(int cause) {
}

// OnConnectionFailedListener:

@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
Analytics.log("GoogleFusedLocationClientConnectionFailed");
if (getListener() != null) {
getListener().onClientStartFailure();
}
}

// LocationListener:

@Override
public void onLocationChanged(Location location) {
Timber.i("Location changed: %s", location.toString());

if (locationListener != null) {
locationListener.onLocationChanged(LocationUtils.sanitizeAccuracy(location, retainMockAccuracy));
}
}

/**
* Helper method for building a GoogleApiClient with the LocationServices API.
*
* @param context The Context for building the GoogleApiClient.
* @return A GoogleApiClient with the LocationServices API.
*/
private static GoogleApiClient locationServicesClientForContext(@NonNull Context context) {
return new GoogleApiClient.Builder(context)
.addApi(LocationServices.API)
.build();
}
}

This file was deleted.

0 comments on commit 7ba3c4f

Please sign in to comment.