Skip to content

feat: add a fallback gps location provider client when gms not available #925

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ public class FlutterLocation
private LocationSettingsRequest mLocationSettingsRequest;
public LocationCallback mLocationCallback;

private boolean needLocationClientFallback = false;

@TargetApi(Build.VERSION_CODES.N)
private OnNmeaMessageListener mMessageListener;

Expand Down Expand Up @@ -420,6 +422,14 @@ public void startRequestingLocation() {
result.error("MISSING_ACTIVITY", "You should not requestLocation activation outside of an activity.", null);
throw new ActivityNotFoundException();
}

if (needLocationClientFallback) {
// fallback
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback,
Looper.myLooper());
return;
}

mSettingsClient.checkLocationSettings(mLocationSettingsRequest)
.addOnSuccessListener(activity, locationSettingsResponse -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Expand Down Expand Up @@ -452,6 +462,12 @@ public void startRequestingLocation() {
}
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback,
Looper.myLooper());
} else if (statusCode == LocationSettingsStatusCodes.API_NOT_CONNECTED) {
// fallback when API available
if (handleFallback(ae)) {
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback,
Looper.myLooper());
}
} else {// This should not happen according to Android documentation but it has been
// observed on some phones.
sendError("UNEXPECTED_ERROR", e.getMessage(), null);
Expand All @@ -460,4 +476,13 @@ public void startRequestingLocation() {
});
}

private boolean handleFallback(ApiException e) {
if (this.activity == null) {
sendError("UNEXPECTED_ERROR", e.getMessage(), null);
return false;
}
needLocationClientFallback = true;
mFusedLocationClient = GPSFusedLocationProviderClient.getClient(activity);
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
package com.lyokone.location;

import android.app.PendingIntent;
import android.content.Context;
import android.location.Location;
import android.location.LocationManager;
import android.os.Looper;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.gms.common.api.Api.ApiOptions.NoOptions;
import com.google.android.gms.common.api.internal.ApiKey;
import com.google.android.gms.location.CurrentLocationRequest;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LastLocationRequest;
import com.google.android.gms.location.LocationAvailability;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.tasks.CancellationToken;
import com.google.android.gms.tasks.Task;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Executor;

public class GPSFusedLocationProviderClient implements FusedLocationProviderClient,
android.location.LocationListener {

private final LocationManager locationManager;

private final List<LocationCallback> locationCallbacks = new LinkedList<>();

private final Object lock = new Object();

public static GPSFusedLocationProviderClient getClient(Context context) {
LocationManager locationManager = (LocationManager) context.getSystemService(
Context.LOCATION_SERVICE);
return new GPSFusedLocationProviderClient(locationManager);
}

private GPSFusedLocationProviderClient(LocationManager locationManager) {
this.locationManager = locationManager;
}

@NonNull
@Override
public Task<Void> flushLocations() {
throw new RuntimeException("method not implement");
}

@NonNull
@Override
public Task<Location> getCurrentLocation(int i, @Nullable CancellationToken cancellationToken) {
throw new RuntimeException("method not implement");
}

@NonNull
@Override
public Task<Location> getCurrentLocation(@NonNull CurrentLocationRequest currentLocationRequest,
@Nullable CancellationToken cancellationToken) {
throw new RuntimeException("method not implement");
}

@NonNull
@Override
public Task<Location> getLastLocation() {
throw new RuntimeException("method not implement");
}

@NonNull
@Override
public Task<Location> getLastLocation(@NonNull LastLocationRequest lastLocationRequest) {
throw new RuntimeException("method not implement");
}

@NonNull
@Override
public Task<LocationAvailability> getLocationAvailability() {
throw new RuntimeException("method not implement");
}

@NonNull
@Override
public Task<Void> removeLocationUpdates(@NonNull PendingIntent pendingIntent) {
throw new RuntimeException("method not implement");
}

@NonNull
@Override
public Task<Void> removeLocationUpdates(@NonNull LocationCallback locationCallback) {
int idx = -1;
for (int i = 0; i < locationCallbacks.size(); i ++) {
if (locationCallbacks.get(i) == locationCallback) {
idx = i;
break;
}
}
if (idx != -1) {
synchronized (lock) {
locationCallbacks.remove(idx);
}
}
return new UnusedTask<>();
}

@NonNull
@Override
public Task<Void> removeLocationUpdates(@NonNull LocationListener locationListener) {
throw new RuntimeException("method not implement");
}

@NonNull
@Override
public Task<Void> requestLocationUpdates(@NonNull LocationRequest locationRequest,
@NonNull PendingIntent pendingIntent) {
throw new RuntimeException("method not implement");
}

@NonNull
@Override
public Task<Void> requestLocationUpdates(@NonNull LocationRequest locationRequest,
@NonNull LocationCallback locationCallback, @Nullable Looper looper) {
synchronized (lock) {
locationCallbacks.add(locationCallback);
}
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
locationRequest.getMinUpdateIntervalMillis(), locationRequest.getMinUpdateDistanceMeters(),
this, looper);
return new UnusedTask<>();
}

@NonNull
@Override
public Task<Void> requestLocationUpdates(@NonNull LocationRequest locationRequest,
@NonNull LocationListener locationListener, @Nullable Looper looper) {
throw new RuntimeException("method not implement");
}

@NonNull
@Override
public Task<Void> requestLocationUpdates(@NonNull LocationRequest locationRequest,
@NonNull Executor executor, @NonNull LocationCallback locationCallback) {
throw new RuntimeException("method not implement");
}

@NonNull
@Override
public Task<Void> requestLocationUpdates(@NonNull LocationRequest locationRequest,
@NonNull Executor executor, @NonNull LocationListener locationListener) {
throw new RuntimeException("method not implement");
}

@NonNull
@Override
public Task<Void> setMockLocation(@NonNull Location location) {
throw new RuntimeException("method not implement");
}

@NonNull
@Override
public Task<Void> setMockMode(boolean b) {
throw new RuntimeException("method not implement");
}

@NonNull
@Override
public ApiKey<NoOptions> getApiKey() {
throw new RuntimeException("method not implement");
}

@Override
public void onLocationChanged(@NonNull Location location) {
List<Location> locations = new ArrayList<>();
locations.add(location);
for (LocationCallback callback : locationCallbacks) {
callback.onLocationResult(LocationResult.create(locations));
}
}

@Override
public void onLocationChanged(@NonNull List<Location> locations) {
for (LocationCallback callback : locationCallbacks) {
callback.onLocationResult(LocationResult.create(locations));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package com.lyokone.location;

import android.app.Activity;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import java.util.concurrent.Executor;

public class UnusedTask<T> extends Task<T> {

@NonNull
@Override
public Task<T> addOnFailureListener(@NonNull OnFailureListener onFailureListener) {
throw new RuntimeException("method not implement");
}

@NonNull
@Override
public Task<T> addOnFailureListener(@NonNull Activity activity,
@NonNull OnFailureListener onFailureListener) {
throw new RuntimeException("method not implement");
}

@NonNull
@Override
public Task<T> addOnFailureListener(@NonNull Executor executor,
@NonNull OnFailureListener onFailureListener) {
throw new RuntimeException("method not implement");
}

@NonNull
@Override
public Task<T> addOnSuccessListener(@NonNull OnSuccessListener<? super T> onSuccessListener) {
throw new RuntimeException("method not implement");
}

@NonNull
@Override
public Task<T> addOnSuccessListener(@NonNull Activity activity,
@NonNull OnSuccessListener<? super T> onSuccessListener) {
throw new RuntimeException("method not implement");
}

@NonNull
@Override
public Task<T> addOnSuccessListener(@NonNull Executor executor,
@NonNull OnSuccessListener<? super T> onSuccessListener) {
throw new RuntimeException("method not implement");
}

@Nullable
@Override
public Exception getException() {
throw new RuntimeException("method not implement");
}

@Override
public T getResult() {
throw new RuntimeException("method not implement");
}

@Override
public <X extends Throwable> T getResult(@NonNull Class<X> aClass) throws X {
throw new RuntimeException("method not implement");
}

@Override
public boolean isCanceled() {
return false;
}

@Override
public boolean isComplete() {
return false;
}

@Override
public boolean isSuccessful() {
return false;
}
}