Skip to content
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

Adds MSL Altitude Support #1029

Closed
wants to merge 5 commits into from
Closed
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
5 changes: 5 additions & 0 deletions geolocator_android/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 3.2.0

- Adds support for receiving NMEA messages in position stream updates.
- Adds support for getting altitude reported as height above MSL.

## 3.1.6

* Switches to a package-internal implementation of the platform interface.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public class GeolocatorPlugin implements FlutterPlugin, ActivityAware {
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG, "Geolocator foreground service connected");
if (service instanceof GeolocatorLocationService.LocalBinder) {
initialize(((GeolocatorLocationService.LocalBinder) service).getLocationService());
initialize(((GeolocatorLocationService.LocalBinder) service).getLocationService());
}
}

Expand All @@ -51,6 +51,7 @@ public void onServiceDisconnected(ComponentName name) {
}
}
};
@Nullable private NmeaStreamHandlerImpl nmeaStreamHandlerImpl;
@Nullable private LocationServiceHandlerImpl locationServiceHandler;

@SuppressWarnings("deprecation")
Expand Down Expand Up @@ -108,6 +109,10 @@ public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBindin
streamHandler.startListening(
flutterPluginBinding.getApplicationContext(), flutterPluginBinding.getBinaryMessenger());

nmeaStreamHandlerImpl = new NmeaStreamHandlerImpl();
nmeaStreamHandlerImpl.startListening(
flutterPluginBinding.getApplicationContext(), flutterPluginBinding.getBinaryMessenger());

locationServiceHandler = new LocationServiceHandlerImpl();
locationServiceHandler.setContext(flutterPluginBinding.getApplicationContext());
locationServiceHandler.startListening(
Expand Down Expand Up @@ -216,6 +221,10 @@ private void dispose() {
streamHandler.setForegroundLocationService(null);
streamHandler = null;
}

if (nmeaStreamHandlerImpl != null) {
nmeaStreamHandlerImpl.stopListening();
}
if (locationServiceHandler != null) {
locationServiceHandler.setContext(null);
locationServiceHandler.stopListening();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package com.baseflow.geolocator;

import android.content.Context;
import android.util.Log;

import androidx.annotation.Nullable;

import com.baseflow.geolocator.location.NmeaClient;
import com.baseflow.geolocator.location.NmeaMapper;

import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.EventChannel;

class NmeaStreamHandlerImpl implements EventChannel.StreamHandler {
private static final String TAG = "FlutterGeolocator";

@Nullable private EventChannel channel;
@Nullable private Context context;
@Nullable private NmeaClient nmeaClient;

public NmeaStreamHandlerImpl() {}

/**
* Registers this instance as event stream handler on the given {@code messenger}.
*
* <p>Stops any previously started and unstopped calls.
*
* <p>This should be cleaned with {@link #stopListening} once the messenger is disposed of.
*/
void startListening(Context context, BinaryMessenger messenger) {
if (channel != null) {
Log.w(TAG, "Setting a event call handler before the last was disposed.");
stopListening();
}

channel = new EventChannel(messenger, "flutter.baseflow.com/geolocator_nmea_updates_android");
channel.setStreamHandler(this);
this.context = context;
this.nmeaClient = new NmeaClient(this.context);
}

/**
* Clears this instance from listening to method calls.
*
* <p>Does nothing if {@link #startListening} hasn't been called, or if we're already stopped.
*/
void stopListening() {
if (channel == null) {
Log.d(TAG, "Tried to stop listening when no MethodChannel had been initialized.");
return;
}

disposeListeners();
channel.setStreamHandler(null);
channel = null;
}

@Override
public void onListen(Object arguments, EventChannel.EventSink events) {

if (nmeaClient == null) {
Log.e(TAG, "NMEA Client has not started correctly");
return;
}

nmeaClient.start();
nmeaClient.setCallback((message -> events.success(NmeaMapper.toHashMap(message))));
}

@Override
public void onCancel(Object arguments) {
disposeListeners();
}

private void disposeListeners() {
Log.e(TAG, "Geolocator position updates stopped");
if (nmeaClient != null) {
nmeaClient.setCallback(null);
nmeaClient.stop();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,35 @@
import android.location.Location;
import android.os.Looper;
import android.util.Log;

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

import com.baseflow.geolocator.errors.ErrorCallback;
import com.baseflow.geolocator.errors.ErrorCodes;
import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.common.api.ResolvableApiException;
import com.google.android.gms.location.*;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationAvailability;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.LocationSettingsRequest;
import com.google.android.gms.location.LocationSettingsResponse;
import com.google.android.gms.location.LocationSettingsStates;
import com.google.android.gms.location.LocationSettingsStatusCodes;
import com.google.android.gms.location.SettingsClient;

import java.util.Random;

class FusedLocationClient implements LocationClient {
private static final String TAG = "FlutterGeolocator";
private static final String TAG = "FlutterGeolocator";

private final Context context;
private final LocationCallback locationCallback;
private final FusedLocationProviderClient fusedLocationProviderClient;
private final NmeaClient nmeaClient;
private final int activityRequestCode;
@Nullable private final LocationOptions locationOptions;

Expand All @@ -33,14 +47,15 @@ public FusedLocationClient(@NonNull Context context, @Nullable LocationOptions l
this.fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(context);
this.locationOptions = locationOptions;
this.activityRequestCode = generateActivityRequestCode();
this.nmeaClient = new NmeaClient(context);

locationCallback =
new LocationCallback() {
@Override
public synchronized void onLocationResult(LocationResult locationResult) {
if (locationResult == null || positionChangedCallback == null) {
Log.e(
TAG,
TAG,
"LocationCallback was called with empty locationResult or no positionChangedCallback was registered.");
fusedLocationProviderClient.removeLocationUpdates(locationCallback);
if (errorCallback != null) {
Expand All @@ -50,6 +65,7 @@ public synchronized void onLocationResult(LocationResult locationResult) {
}

Location location = locationResult.getLastLocation();
nmeaClient.enrichExtrasWithNmea(location);
positionChangedCallback.onPositionChanged(location);
}

Expand All @@ -65,16 +81,53 @@ public synchronized void onLocationAvailability(
};
}

private static LocationRequest buildLocationRequest(@Nullable LocationOptions options) {
LocationRequest locationRequest = new LocationRequest();

if (options != null) {
locationRequest.setPriority(toPriority(options.getAccuracy()));
locationRequest.setInterval(options.getTimeInterval());
locationRequest.setFastestInterval(options.getTimeInterval() / 2);
locationRequest.setSmallestDisplacement(options.getDistanceFilter());
}

return locationRequest;
}

private static LocationSettingsRequest buildLocationSettingsRequest(
LocationRequest locationRequest) {
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(locationRequest);

return builder.build();
}

private static int toPriority(LocationAccuracy locationAccuracy) {
switch (locationAccuracy) {
case lowest:
return LocationRequest.PRIORITY_NO_POWER;
case low:
return LocationRequest.PRIORITY_LOW_POWER;
case medium:
return LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY;
default:
return LocationRequest.PRIORITY_HIGH_ACCURACY;
}
}

private synchronized int generateActivityRequestCode() {
Random random = new Random();
return random.nextInt(1 << 16);
}

@SuppressLint("MissingPermission")
private void requestPositionUpdates(LocationOptions locationOptions) {
if (locationOptions != null && locationOptions.getUseMSLAltitude()) {
this.nmeaClient.start();
}
LocationRequest locationRequest = buildLocationRequest(locationOptions);
fusedLocationProviderClient.requestLocationUpdates(
locationRequest, locationCallback, Looper.getMainLooper());
locationRequest, locationCallback, Looper.getMainLooper());
}

@Override
Expand Down Expand Up @@ -151,9 +204,7 @@ public void startPositionUpdates(
settingsClient
.checkLocationSettings(settingsRequest)
.addOnSuccessListener(
locationSettingsResponse ->
requestPositionUpdates(this.locationOptions)
)
locationSettingsResponse -> requestPositionUpdates(this.locationOptions))
.addOnFailureListener(
e -> {
if (e instanceof ResolvableApiException) {
Expand Down Expand Up @@ -193,39 +244,6 @@ public void startPositionUpdates(

public void stopPositionUpdates() {
fusedLocationProviderClient.removeLocationUpdates(locationCallback);
}

private static LocationRequest buildLocationRequest(@Nullable LocationOptions options) {
LocationRequest locationRequest = new LocationRequest();

if (options != null) {
locationRequest.setPriority(toPriority(options.getAccuracy()));
locationRequest.setInterval(options.getTimeInterval());
locationRequest.setFastestInterval(options.getTimeInterval() / 2);
locationRequest.setSmallestDisplacement(options.getDistanceFilter());
}

return locationRequest;
}

private static LocationSettingsRequest buildLocationSettingsRequest(
LocationRequest locationRequest) {
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(locationRequest);

return builder.build();
}

private static int toPriority(LocationAccuracy locationAccuracy) {
switch (locationAccuracy) {
case lowest:
return LocationRequest.PRIORITY_NO_POWER;
case low:
return LocationRequest.PRIORITY_LOW_POWER;
case medium:
return LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY;
default:
return LocationRequest.PRIORITY_HIGH_ACCURACY;
}
this.nmeaClient.stop();
}
}
Loading