diff --git a/.github/workflows/geolocator_web.yaml b/.github/workflows/geolocator_web.yaml index e09d3a0b1..0cc97fc51 100644 --- a/.github/workflows/geolocator_web.yaml +++ b/.github/workflows/geolocator_web.yaml @@ -23,6 +23,7 @@ jobs: env: source-directory: ./geolocator_web + example-directory: ./geolocator_web/example # Steps represent a sequence of tasks that will be executed as part of the job steps: @@ -51,5 +52,5 @@ jobs: # Build Web version of the example App - name: Run Web build - run: flutter build web --release --no-sound-null-safety + run: flutter build web --release working-directory: ${{env.example-directory}} diff --git a/README.md b/README.md index 74ed23e8a..f34b0d4e9 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,10 @@ The Flutter geolocator plugin is built following the federated plugin architectu 1. [`geolocator`][1]: the app facing package. This is the package users depend on to use the plugin in their project. For details on how to use the [`geolocator`][1] plugin you can refer to its [README.md][2] file. 2. [`geolocator_android`][3]: this package contains the endorsed Android implementation of the geolocator_platform_interface and adds Android support to the [`geolocator`][1] app facing package. More information can be found in its [README.md][4] file; -2. [`geolocator_apple`][5]: this package contains the endorsed iOS and macOS implementations of the geolocator_platform_interface and adds iOS and macOS support to the [`geolocator`][1] app facing package. More information can be found in its [README.md][6] file; -2. [`geolocator_web`][7]: this package contains the endorsed web implementation of the geolocator_platform_interface and adds web support to the [`geolocator`][1] app facing package. More information can be found in its [README.md][8] file; -2. [`geolocator_windows`][9]: this package contains the endorsed Windows implementation of the geolocator_platform_interface and adds Windows support to the [`geolocator`][1] app facing package. More information can be found in its [README.md][10] file; -3. [`geolocator_platform_interface`][11]: this package declares the interface which all platform packages must implement to support the app-facing package. Instructions on how to implement a platform package can be found in the [README.md][12] of the [`geolocator_platform_interface`][11] package. +3. [`geolocator_apple`][5]: this package contains the endorsed iOS and macOS implementations of the geolocator_platform_interface and adds iOS and macOS support to the [`geolocator`][1] app facing package. More information can be found in its [README.md][6] file; +4. [`geolocator_web`][7]: this package contains the endorsed web implementation of the geolocator_platform_interface and adds web support to the [`geolocator`][1] app facing package. More information can be found in its [README.md][8] file; +5. [`geolocator_windows`][9]: this package contains the endorsed Windows implementation of the geolocator_platform_interface and adds Windows support to the [`geolocator`][1] app facing package. More information can be found in its [README.md][10] file; +6. [`geolocator_platform_interface`][11]: this package declares the interface which all platform packages must implement to support the app-facing package. Instructions on how to implement a platform package can be found in the [README.md][12] of the [`geolocator_platform_interface`][11] package. [1]: ./geolocator [2]: ./geolocator/README.md diff --git a/geolocator/CHANGELOG.md b/geolocator/CHANGELOG.md index dfaa56efa..b42639577 100644 --- a/geolocator/CHANGELOG.md +++ b/geolocator/CHANGELOG.md @@ -1,6 +1,15 @@ +## 10.1.1 + +- Replaced optional DateTime? `timestamp` in `Position` object for an NonNull DateTime `timestamp`. + +## 10.1.0 + +- Includes `altitudeAccuracy` and `headingAccuracy` in `Position`. + ## 10.0.1 -- Optional timestamp in Position object is not optional anymore. +- Updates documentation for `getCurrentPosition()`, to clarify the behavior of location accuracy on Android devices. +- Updates README regarding the plugin interpretation of `LocationAccuracy`. ## 10.0.0 diff --git a/geolocator/README.md b/geolocator/README.md index eefc00bdd..78e462618 100644 --- a/geolocator/README.md +++ b/geolocator/README.md @@ -409,16 +409,28 @@ double bearing = Geolocator.bearingBetween(52.2165157, 6.9437819, 52.3546274, 4. ### Location accuracy -The table below outlines the accuracy options per platform: - -| | Android | iOS | -|------------|-----------:|------:| -| **lowest** | 500m | 3000m | -| **low** | 500m | 1000m | -| **medium** | 100 - 500m | 100m | -| **high** | 0 - 100m | 10m | -| **best** | 0 - 100m | ~0m | -| **bestForNavigation** | 0 - 100m | [Optimized for navigation](https://developer.apple.com/documentation/corelocation/kcllocationaccuracybestfornavigation) | +#### Android +On Android, the `LocationAccuracy` enum controls the accuracy of the location data the app wants to receive. It also provides control over the [priority given to the location stream](https://developers.google.com/android/reference/com/google/android/gms/location/Priority). This can be confusing, as a priority of **lowest** might not return any location, while one might expect it to give the quickest responses. The table below outlines the priority and its meaning per accuracy option: + +| Location accuracy | Android priority | Description | +|-------------------|------------------|-------------| +| **lowest** | [PRIORITY_PASSIVE](https://developers.google.com/android/reference/com/google/android/gms/location/Priority#public-static-final-int-priority_passive) | Ensures that no extra power will be used to derive locations. This enforces that the request will act as a passive listener that will only receive "free" locations calculated on behalf of other clients, and no locations will be calculated on behalf of only this request. | +| **low** | [PRIORITY_LOW_POWER](https://developers.google.com/android/reference/com/google/android/gms/location/Priority#public-static-final-int-priority_low_power) | Requests a tradeoff that favors low power usage at the possible expense of location accuracy. | +| **medium** | [PRIORITY_BALANCED_POWER_ACCURACY](https://developers.google.com/android/reference/com/google/android/gms/location/Priority#public-static-final-int-priority_balanced_power_accuracy) | Requests a tradeoff that is balanced between location accuracy and power usage. | +| **high**+ | [PRIORITY_HIGH_ACCURACY](https://developers.google.com/android/reference/com/google/android/gms/location/Priority#public-static-final-int-priority_high_accuracy) | Requests a tradeoff that favors highly accurate locations at the possible expense of additional power usage. | + +#### iOS +On iOS, the `LocationAccuracy` enum controls the accuracy of the location data the app wants to receive. It also provides control on the battery consumption of the device: the more detailed data is requested, the larger the impact on the battery consumption. More details can be found on [Apple's documentation](https://developer.apple.com/documentation/corelocation/cllocationmanager/1423836-desiredaccuracy?language=objc). The table below shows how the `LocationAccuracy` values map to the native iOS accuracy settings. + +| Location accuracy | iOS accuracy | Description | +|---|---|---| +| **lowest** | [kCLLocationAccuracyThreeKilometers](https://developer.apple.com/documentation/corelocation/kcllocationaccuracythreekilometers?language=objc) | Accurate to the nearest three kilometers. | +| **low** | [kCLLocationAccuracyKilometer](https://developer.apple.com/documentation/corelocation/kcllocationaccuracykilometer?language=objc) | Accurate to the nearest kilometer. | +| **medium** | [kCLLocationAccuracyHundredMeters](https://developer.apple.com/documentation/corelocation/kcllocationaccuracyhundredmeters?language=objc) | Accurate to within one hundred meters. | +| **high** | [kCLLocationAccuracyNearestTenMeters](https://developer.apple.com/documentation/corelocation/kcllocationaccuracynearesttenmeters?language=objc) | Accurate to within ten meters of the desired target. | +| **best** | [kCLLocationAccuracyBest](https://developer.apple.com/documentation/corelocation/kcllocationaccuracybest?language=objc) | The best level of accuracy available. | +| **bestForNavigation** | [kCLLocationAccuracyBestForNavigation](https://developer.apple.com/documentation/corelocation/kcllocationaccuracybestfornavigation?language=objc) | The highest possible accuracy that uses additional sensor data to facilitate navigation apps. | + ## Issues diff --git a/geolocator/example/windows/flutter/generated_plugins.cmake b/geolocator/example/windows/flutter/generated_plugins.cmake index c9e02adbf..f0bcafdb9 100644 --- a/geolocator/example/windows/flutter/generated_plugins.cmake +++ b/geolocator/example/windows/flutter/generated_plugins.cmake @@ -7,6 +7,9 @@ list(APPEND FLUTTER_PLUGIN_LIST url_launcher_windows ) +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + set(PLUGIN_BUNDLED_LIBRARIES) foreach(plugin ${FLUTTER_PLUGIN_LIST}) @@ -15,3 +18,8 @@ foreach(plugin ${FLUTTER_PLUGIN_LIST}) list(APPEND PLUGIN_BUNDLED_LIBRARIES $) list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/geolocator/lib/geolocator.dart b/geolocator/lib/geolocator.dart index 4b566e89c..86311aa72 100644 --- a/geolocator/lib/geolocator.dart +++ b/geolocator/lib/geolocator.dart @@ -54,20 +54,48 @@ class Geolocator { GeolocatorPlatform.instance.getLastKnownPosition( forceLocationManager: forceAndroidLocationManager); - /// Returns the current position taking the supplied [desiredAccuracy] into - /// account. + /// Returns the current position. /// /// You can control the precision of the location updates by supplying the - /// [desiredAccuracy] parameter (defaults to "best"). On Android you can - /// force the use of the Android LocationManager instead of the - /// FusedLocationProvider by setting the [forceAndroidLocationManager] + /// [desiredAccuracy] parameter (defaults to "best"). + /// On Android you can force the use of the Android LocationManager instead of + /// the FusedLocationProvider by setting the [forceAndroidLocationManager] /// parameter to true. The [timeLimit] parameter allows you to specify a /// timeout interval (by default no time limit is configured). /// + /// Calling the [getCurrentPosition] method will request the platform to + /// obtain a location fix. Depending on the availability of different location + /// services, this can take several seconds. The recommended use would be to + /// call the [getLastKnownPosition] method to receive a cached position and + /// update it with the result of the [getCurrentPosition] method. + /// /// Throws a [TimeoutException] when no location is received within the /// supplied [timeLimit] duration. /// Throws a [LocationServiceDisabledException] when the user allowed access, /// but the location services of the device are disabled. + /// + /// + /// **Note**: On Android the location *accuracy* is interpreted as + /// [location *priority*](https://developers.google.com/android/reference/com/google/android/gms/location/Priority#constants). + /// The interpretation works as follows: + /// + /// [LocationAccuracy.lowest] -> [PRIORITY_PASSIVE](https://developers.google.com/android/reference/com/google/android/gms/location/Priority#public-static-final-int-priority_passive): + /// Ensures that no extra power will be used to derive locations. This + /// enforces that the request will act as a passive listener that will only + /// receive "free" locations calculated on behalf of other clients, and no + /// locations will be calculated on behalf of only this request. + /// + /// [LocationAccuracy.low] -> [PRIORITY_LOW_POWER](https://developers.google.com/android/reference/com/google/android/gms/location/Priority#public-static-final-int-priority_low_power): + /// Requests a tradeoff that favors low power usage at the possible expense of + /// location accuracy. + /// + /// [LocationAccuracy.medium] -> [PRIORITY_BALANCED_POWER_ACCURACY](https://developers.google.com/android/reference/com/google/android/gms/location/Priority#public-static-final-int-priority_balanced_power_accuracy): + /// Requests a tradeoff that is balanced between location accuracy and power + /// usage. + /// + /// [LocationAccuracy.high]+ -> [PRIORITY_HIGH_ACCURACY](https://developers.google.com/android/reference/com/google/android/gms/location/Priority#public-static-final-int-priority_high_accuracy): + /// Requests a tradeoff that favors highly accurate locations at the possible + /// expense of additional power usage. static Future getCurrentPosition({ LocationAccuracy desiredAccuracy = LocationAccuracy.best, bool forceAndroidLocationManager = false, diff --git a/geolocator/pubspec.yaml b/geolocator/pubspec.yaml index ce18b57cc..bfbf5e7cf 100644 --- a/geolocator/pubspec.yaml +++ b/geolocator/pubspec.yaml @@ -2,7 +2,7 @@ name: geolocator description: Geolocation plugin for Flutter. This plugin provides a cross-platform (iOS, Android) API for generic location (GPS etc.) functions. repository: https://github.com/baseflow/flutter-geolocator/tree/main/geolocator issue_tracker: https://github.com/baseflow/flutter-geolocator/issues?q=is%3Aissue+is%3Aopen -version: 10.0.0 +version: 10.1.0 environment: sdk: ">=2.15.0 <4.0.0" @@ -26,11 +26,11 @@ dependencies: flutter: sdk: flutter - geolocator_platform_interface: ^4.0.3 - geolocator_android: ^4.1.3 - geolocator_apple: ^2.1.1+1 - geolocator_web: ^2.1.3 - geolocator_windows: ^0.2.0 + geolocator_platform_interface: ^4.1.0 + geolocator_android: ^4.3.0 + geolocator_apple: ^2.3.0 + geolocator_web: ^2.2.0 + geolocator_windows: ^0.2.2 dev_dependencies: flutter_test: diff --git a/geolocator/test/geolocator_test.dart b/geolocator/test/geolocator_test.dart index 185a0d488..59099a9fb 100644 --- a/geolocator/test/geolocator_test.dart +++ b/geolocator/test/geolocator_test.dart @@ -12,8 +12,10 @@ Position get mockPosition => Position( isUtc: true, ), altitude: 3000.0, + altitudeAccuracy: 0.0, accuracy: 0.0, heading: 0.0, + headingAccuracy: 0.0, speed: 0.0, speedAccuracy: 0.0); diff --git a/geolocator_android/CHANGELOG.md b/geolocator_android/CHANGELOG.md index d678b5822..461405f39 100644 --- a/geolocator_android/CHANGELOG.md +++ b/geolocator_android/CHANGELOG.md @@ -1,3 +1,30 @@ +## 4.3.3 + +- Removes deprecated support for Android V1 embedding from the JAVA code base. Note that the geolocator's Flutter version restrictions already don't support V1 embedding anymore. +- Registers location services state change broadcast receiver with required exported flags + +## 4.3.2 + +- Updates the following dependencies: + - uuid package from ^3.0.7 to ^4.1.0 + - flutter_lints from ^2.0.0 to ^3.0.0 + +## 4.3.1 + +- Suppresses a deprecation warning for `LocationListenerCompat.onStatusChanged` when building for Android. + +## 4.3.0 + +* Includes `altitudeAccuracy` and `headingAccuracy` in `Position`. + +## 4.2.4 + +* Fixes a bug where location readings were very inaccurate when using `forceLocationManager: true`. + +## 4.2.3 + +* Fixes a bug where the position stream was unnecessarily filtered when using `forceLocationManager: true`. + ## 4.2.2 * Adds back the `applicationId` property of the AndroidManifest.xml file to keep backwardscompatibility with older applications that still rely on Gradle version <7.0. diff --git a/geolocator_android/android/src/main/java/com/baseflow/geolocator/GeolocatorPlugin.java b/geolocator_android/android/src/main/java/com/baseflow/geolocator/GeolocatorPlugin.java index 8fdd10779..9d16cdede 100644 --- a/geolocator_android/android/src/main/java/com/baseflow/geolocator/GeolocatorPlugin.java +++ b/geolocator_android/android/src/main/java/com/baseflow/geolocator/GeolocatorPlugin.java @@ -53,10 +53,6 @@ public void onServiceDisconnected(ComponentName name) { }; @Nullable private LocationServiceHandlerImpl locationServiceHandler; - @SuppressWarnings("deprecation") - @Nullable - private io.flutter.plugin.common.PluginRegistry.Registrar pluginRegistrar; - @Nullable private ActivityPluginBinding pluginBinding; public GeolocatorPlugin() { @@ -65,38 +61,6 @@ public GeolocatorPlugin() { locationAccuracyManager = new LocationAccuracyManager(); } - // This static function is optional and equivalent to onAttachedToEngine. It supports the old - // pre-Flutter-1.12 Android projects. You are encouraged to continue supporting - // plugin registration via this function while apps migrate to use the new Android APIs - // post-flutter-1.12 via https://flutter.dev/go/android-project-migration. - // - // It is encouraged to share logic between onAttachedToEngine and registerWith to keep - // them functionally equivalent. Only one of onAttachedToEngine or registerWith will be called - // depending on the user's project. onAttachedToEngine or registerWith must both be defined - // in the same class. - @SuppressWarnings("deprecation") - public static void registerWith(io.flutter.plugin.common.PluginRegistry.Registrar registrar) { - GeolocatorPlugin geolocatorPlugin = new GeolocatorPlugin(); - geolocatorPlugin.pluginRegistrar = registrar; - geolocatorPlugin.registerListeners(); - - MethodCallHandlerImpl methodCallHandler = - new MethodCallHandlerImpl( - geolocatorPlugin.permissionManager, - geolocatorPlugin.geolocationManager, - geolocatorPlugin.locationAccuracyManager); - methodCallHandler.startListening(registrar.context(), registrar.messenger()); - methodCallHandler.setActivity(registrar.activity()); - - StreamHandlerImpl streamHandler = new StreamHandlerImpl(geolocatorPlugin.permissionManager); - streamHandler.startListening(registrar.context(), registrar.messenger()); - - LocationServiceHandlerImpl locationServiceHandler = new LocationServiceHandlerImpl(); - locationServiceHandler.startListening(registrar.context(), registrar.messenger()); - locationServiceHandler.setContext(registrar.activeContext()); - geolocatorPlugin.bindForegroundService(registrar.activeContext()); - } - @Override public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) { methodCallHandler = @@ -168,10 +132,7 @@ public void onDetachedFromActivity() { } private void registerListeners() { - if (pluginRegistrar != null) { - pluginRegistrar.addActivityResultListener(this.geolocationManager); - pluginRegistrar.addRequestPermissionsResultListener(this.permissionManager); - } else if (pluginBinding != null) { + if (pluginBinding != null) { pluginBinding.addActivityResultListener(this.geolocationManager); pluginBinding.addRequestPermissionsResultListener(this.permissionManager); } diff --git a/geolocator_android/android/src/main/java/com/baseflow/geolocator/LocationServiceHandlerImpl.java b/geolocator_android/android/src/main/java/com/baseflow/geolocator/LocationServiceHandlerImpl.java index 46ef11a0e..65c6ee61f 100644 --- a/geolocator_android/android/src/main/java/com/baseflow/geolocator/LocationServiceHandlerImpl.java +++ b/geolocator_android/android/src/main/java/com/baseflow/geolocator/LocationServiceHandlerImpl.java @@ -1,6 +1,5 @@ package com.baseflow.geolocator; -import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -8,6 +7,7 @@ import android.util.Log; import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; import com.baseflow.geolocator.location.LocationServiceStatusReceiver; @@ -55,7 +55,7 @@ public void onListen(Object arguments, EventChannel.EventSink events) { IntentFilter filter = new IntentFilter(LocationManager.PROVIDERS_CHANGED_ACTION); filter.addAction(Intent.ACTION_PROVIDER_CHANGED); receiver = new LocationServiceStatusReceiver(events); - context.registerReceiver(receiver, filter); + ContextCompat.registerReceiver(context, receiver, filter, ContextCompat.RECEIVER_EXPORTED); } @Override diff --git a/geolocator_android/android/src/main/java/com/baseflow/geolocator/location/GeolocationManager.java b/geolocator_android/android/src/main/java/com/baseflow/geolocator/location/GeolocationManager.java index c1b6cbe7c..2c706ea26 100644 --- a/geolocator_android/android/src/main/java/com/baseflow/geolocator/location/GeolocationManager.java +++ b/geolocator_android/android/src/main/java/com/baseflow/geolocator/location/GeolocationManager.java @@ -15,7 +15,6 @@ import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; -@SuppressWarnings("deprecation") public class GeolocationManager implements io.flutter.plugin.common.PluginRegistry.ActivityResultListener { diff --git a/geolocator_android/android/src/main/java/com/baseflow/geolocator/location/LocationManagerClient.java b/geolocator_android/android/src/main/java/com/baseflow/geolocator/location/LocationManagerClient.java index a6e29612a..a57054d15 100644 --- a/geolocator_android/android/src/main/java/com/baseflow/geolocator/location/LocationManagerClient.java +++ b/geolocator_android/android/src/main/java/com/baseflow/geolocator/location/LocationManagerClient.java @@ -4,22 +4,24 @@ import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; -import android.location.Criteria; import android.location.Location; -import android.location.LocationListener; import android.location.LocationManager; +import android.os.Build; import android.os.Bundle; import android.os.Looper; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.location.LocationListenerCompat; +import androidx.core.location.LocationManagerCompat; +import androidx.core.location.LocationRequestCompat; import com.baseflow.geolocator.errors.ErrorCallback; import com.baseflow.geolocator.errors.ErrorCodes; import java.util.List; -class LocationManagerClient implements LocationClient, LocationListener { +class LocationManagerClient implements LocationClient, LocationListenerCompat { private static final long TWO_MINUTES = 120000; private final LocationManager locationManager; @@ -73,60 +75,40 @@ static boolean isBetterLocation(Location location, Location bestLocation) { return false; } - private static String getBestProvider( - LocationManager locationManager, LocationAccuracy accuracy) { - Criteria criteria = new Criteria(); - - criteria.setBearingRequired(false); - criteria.setAltitudeRequired(false); - criteria.setSpeedRequired(false); - - switch (accuracy) { - case lowest: - criteria.setAccuracy(Criteria.NO_REQUIREMENT); - criteria.setHorizontalAccuracy(Criteria.NO_REQUIREMENT); - criteria.setPowerRequirement(Criteria.NO_REQUIREMENT); - break; - case low: - criteria.setAccuracy(Criteria.ACCURACY_COARSE); - criteria.setHorizontalAccuracy(Criteria.ACCURACY_LOW); - criteria.setPowerRequirement(Criteria.NO_REQUIREMENT); - break; - case medium: - criteria.setAccuracy(Criteria.ACCURACY_COARSE); - criteria.setHorizontalAccuracy(Criteria.ACCURACY_MEDIUM); - criteria.setPowerRequirement(Criteria.POWER_MEDIUM); - break; - default: - criteria.setAccuracy(Criteria.ACCURACY_FINE); - criteria.setHorizontalAccuracy(Criteria.ACCURACY_HIGH); - criteria.setPowerRequirement(Criteria.POWER_HIGH); - break; - } - - String provider = locationManager.getBestProvider(criteria, true); - - if (provider.trim().isEmpty()) { - List providers = locationManager.getProviders(true); - if (providers.size() > 0) provider = providers.get(0); - } - - return provider; + private static @Nullable String determineProvider( + @NonNull LocationManager locationManager, + @NonNull LocationAccuracy accuracy) { + + final List enabledProviders = locationManager.getProviders(true); + + if (accuracy == LocationAccuracy.lowest) { + return LocationManager.PASSIVE_PROVIDER; + } else if (enabledProviders.contains(LocationManager.FUSED_PROVIDER) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + return LocationManager.FUSED_PROVIDER; + } else if (enabledProviders.contains(LocationManager.GPS_PROVIDER)) { + return LocationManager.GPS_PROVIDER; + } else if (enabledProviders.contains(LocationManager.NETWORK_PROVIDER)) { + return LocationManager.NETWORK_PROVIDER; + } else if (!enabledProviders.isEmpty()){ + return enabledProviders.get(0); + } else { + return null; + } } - private static float accuracyToFloat(LocationAccuracy accuracy) { - switch (accuracy) { - case lowest: - case low: - return 500; - case medium: - return 250; - case best: - case bestForNavigation: - return 50; - default: - return 100; - } + private static @LocationRequestCompat.Quality int accuracyToQuality(@NonNull LocationAccuracy accuracy) { + switch (accuracy) { + case lowest: + case low: + return LocationRequestCompat.QUALITY_LOW_POWER; + case high: + case best: + case bestForNavigation: + return LocationRequestCompat.QUALITY_HIGH_ACCURACY; + case medium: + default: + return LocationRequestCompat.QUALITY_BALANCED_POWER_ACCURACY; + } } @Override @@ -176,27 +158,41 @@ public void startPositionUpdates( this.positionChangedCallback = positionChangedCallback; this.errorCallback = errorCallback; - LocationAccuracy locationAccuracy = - this.locationOptions != null ? this.locationOptions.getAccuracy() : LocationAccuracy.best; + LocationAccuracy accuracy = LocationAccuracy.best; + long timeInterval = 0; + float distanceFilter = 0; + @LocationRequestCompat.Quality int quality = LocationRequestCompat.QUALITY_BALANCED_POWER_ACCURACY; - this.currentLocationProvider = getBestProvider(this.locationManager, locationAccuracy); + if (this.locationOptions != null) { + distanceFilter = locationOptions.getDistanceFilter(); + accuracy = locationOptions.getAccuracy(); + timeInterval = accuracy == LocationAccuracy.lowest + ? LocationRequestCompat.PASSIVE_INTERVAL + : locationOptions.getTimeInterval(); + quality = accuracyToQuality(accuracy); + } + + this.currentLocationProvider = determineProvider(this.locationManager, accuracy); - if (this.currentLocationProvider.trim().isEmpty()) { + if (this.currentLocationProvider == null) { errorCallback.onError(ErrorCodes.locationServicesDisabled); return; } - long timeInterval = 0; - float distanceFilter = 0; - if (this.locationOptions != null) { - timeInterval = locationOptions.getTimeInterval(); - distanceFilter = locationOptions.getDistanceFilter(); - } + final LocationRequestCompat locationRequest = new LocationRequestCompat.Builder(timeInterval) + .setMinUpdateDistanceMeters(distanceFilter) + .setQuality(quality) + .build(); this.isListening = true; this.nmeaClient.start(); - this.locationManager.requestLocationUpdates( - this.currentLocationProvider, timeInterval, distanceFilter, this, Looper.getMainLooper()); + + LocationManagerCompat.requestLocationUpdates( + this.locationManager, + this.currentLocationProvider, + locationRequest, + this, + Looper.getMainLooper()); } @SuppressLint("MissingPermission") @@ -209,11 +205,7 @@ public void stopPositionUpdates() { @Override public synchronized void onLocationChanged(Location location) { - float desiredAccuracy = - locationOptions != null ? accuracyToFloat(locationOptions.getAccuracy()) : 50; - - if (isBetterLocation(location, currentBestLocation) - && location.getAccuracy() <= desiredAccuracy) { + if (isBetterLocation(location, currentBestLocation)) { this.currentBestLocation = location; if (this.positionChangedCallback != null) { @@ -223,10 +215,16 @@ public synchronized void onLocationChanged(Location location) { } } + /** + * This callback will never be invoked on Android Q and above, and providers can be considered as + * always in the {@link android.location.LocationProvider#AVAILABLE} state. + * See the Android documentation + * for more information. + */ + @SuppressWarnings({"deprecation", "RedundantSuppression"}) @TargetApi(28) - @SuppressWarnings("deprecation") @Override - public void onStatusChanged(String provider, int status, Bundle extras) { + public void onStatusChanged(@NonNull String provider, int status, Bundle extras) { if (status == android.location.LocationProvider.AVAILABLE) { onProviderEnabled(provider); } else if (status == android.location.LocationProvider.OUT_OF_SERVICE) { @@ -235,7 +233,7 @@ public void onStatusChanged(String provider, int status, Bundle extras) { } @Override - public void onProviderEnabled(String provider) {} + public void onProviderEnabled(@NonNull String provider) {} @SuppressLint("MissingPermission") @Override diff --git a/geolocator_android/android/src/main/java/com/baseflow/geolocator/location/LocationMapper.java b/geolocator_android/android/src/main/java/com/baseflow/geolocator/location/LocationMapper.java index a9ac9ac20..1afaf40da 100644 --- a/geolocator_android/android/src/main/java/com/baseflow/geolocator/location/LocationMapper.java +++ b/geolocator_android/android/src/main/java/com/baseflow/geolocator/location/LocationMapper.java @@ -20,8 +20,12 @@ public static Map toHashMap(Location location) { position.put("is_mocked", isMocked(location)); if (location.hasAltitude()) position.put("altitude", location.getAltitude()); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && location.hasVerticalAccuracy()) + position.put("altitude_accuracy", location.getVerticalAccuracyMeters()); if (location.hasAccuracy()) position.put("accuracy", (double) location.getAccuracy()); if (location.hasBearing()) position.put("heading", (double) location.getBearing()); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && location.hasBearingAccuracy()) + position.put("heading_accuracy", location.getBearingAccuracyDegrees()); if (location.hasSpeed()) position.put("speed", (double) location.getSpeed()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && location.hasSpeedAccuracy()) position.put("speed_accuracy", (double) location.getSpeedAccuracyMetersPerSecond()); diff --git a/geolocator_android/android/src/main/java/com/baseflow/geolocator/location/NotificationImportance.java b/geolocator_android/android/src/main/java/com/baseflow/geolocator/location/NotificationImportance.java deleted file mode 100644 index bf9b94262..000000000 --- a/geolocator_android/android/src/main/java/com/baseflow/geolocator/location/NotificationImportance.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.baseflow.geolocator.location; - -public enum NotificationImportance { - Default, - High, - Max, -} diff --git a/geolocator_android/example/android/gradle.properties b/geolocator_android/example/android/gradle.properties index 94adc3a3f..d9cf55df7 100644 --- a/geolocator_android/example/android/gradle.properties +++ b/geolocator_android/example/android/gradle.properties @@ -1,3 +1,2 @@ org.gradle.jvmargs=-Xmx1536M android.useAndroidX=true -android.enableJetifier=true diff --git a/geolocator_android/pubspec.yaml b/geolocator_android/pubspec.yaml index a986d009d..d4c55d3e8 100644 --- a/geolocator_android/pubspec.yaml +++ b/geolocator_android/pubspec.yaml @@ -2,7 +2,7 @@ name: geolocator_android description: Geolocation plugin for Flutter. This plugin provides the Android implementation for the geolocator. repository: https://github.com/baseflow/flutter-geolocator/tree/main/geolocator_android issue_tracker: https://github.com/baseflow/flutter-geolocator/issues?q=is%3Aissue+is%3Aopen -version: 4.2.2 +version: 4.3.3 environment: sdk: ">=2.15.0 <4.0.0" @@ -20,13 +20,13 @@ flutter: dependencies: flutter: sdk: flutter - geolocator_platform_interface: ^4.0.4 - uuid: ^3.0.7 + geolocator_platform_interface: ^4.1.0 + uuid: ^4.1.0 dev_dependencies: async: ^2.8.2 flutter_test: sdk: flutter - flutter_lints: ^2.0.1 + flutter_lints: ^3.0.0 mockito: ^5.2.0 plugin_platform_interface: ^2.1.2 diff --git a/geolocator_android/test/geolocator_android_test.dart b/geolocator_android/test/geolocator_android_test.dart index 17599b0ec..bd217fccd 100644 --- a/geolocator_android/test/geolocator_android_test.dart +++ b/geolocator_android/test/geolocator_android_test.dart @@ -16,8 +16,10 @@ Position get mockPosition => Position( isUtc: true, ), altitude: 3000.0, + altitudeAccuracy: 0.0, accuracy: 0.0, heading: 0.0, + headingAccuracy: 0.0, speed: 0.0, speedAccuracy: 0.0, isMocked: false); diff --git a/geolocator_apple/CHANGELOG.md b/geolocator_apple/CHANGELOG.md index 675b2de92..7ba7387e5 100644 --- a/geolocator_apple/CHANGELOG.md +++ b/geolocator_apple/CHANGELOG.md @@ -1,3 +1,15 @@ +## 2.3.2 + +* Fixes build error and warnings regarding unused variables and unavailable APIs on macOS. + +## 2.3.1 + +* Fixes a bug where invalid speed and speed accuracy readings where returned instead of ignored. + +## 2.3.0 + +* Includes `altitudeAccuracy` and `headingAccuracy` in `Position`. + ## 2.2.7 * Fixes the propagation of the activity type setting. diff --git a/geolocator_apple/example/ios/Runner.xcodeproj/project.pbxproj b/geolocator_apple/example/ios/Runner.xcodeproj/project.pbxproj index a180eb31b..2608a3854 100644 --- a/geolocator_apple/example/ios/Runner.xcodeproj/project.pbxproj +++ b/geolocator_apple/example/ios/Runner.xcodeproj/project.pbxproj @@ -227,7 +227,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { diff --git a/geolocator_apple/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/geolocator_apple/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 3d55b2d2a..4a7e772c9 100644 --- a/geolocator_apple/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/geolocator_apple/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ = 140000 if (@available(iOS 10.0, *)) { speedAccuracy = location.speedAccuracy; } #endif + if (speed >= 0 && speedAccuracy >= 0) { + [locationMap setObject:@(speed) forKey: @"speed"]; + [locationMap setObject:@(speedAccuracy) forKey: @"speed_accuracy"]; + } - NSMutableDictionary *locationMap = [[NSMutableDictionary alloc]initWithCapacity:9]; - [locationMap setObject:@(location.coordinate.latitude) forKey: @"latitude"]; - [locationMap setObject:@(location.coordinate.longitude) forKey: @"longitude"]; - [locationMap setObject:@(timestamp) forKey: @"timestamp"]; - [locationMap setObject:@(location.altitude) forKey: @"altitude"]; - [locationMap setObject:@(location.horizontalAccuracy) forKey: @"accuracy"]; - [locationMap setObject:@(location.speed) forKey: @"speed"]; - [locationMap setObject:@(speedAccuracy) forKey: @"speed_accuracy"]; - [locationMap setObject:@(location.course) forKey: @"heading"]; + // When verticalAccuracy contains 0 or a negative number, the value of altitude is invalid. + // + // Relevant documentation: + // - https://developer.apple.com/documentation/corelocation/cllocation/1423820-altitude?language=objc + // - https://developer.apple.com/documentation/corelocation/cllocation/1423550-verticalaccuracy?language=objc + double altitudeAccuracy = location.verticalAccuracy; + if (altitudeAccuracy > 0.0) { + [locationMap setObject:@(location.altitude) forKey: @"altitude"]; + [locationMap setObject:@(altitudeAccuracy) forKey: @"altitude_accuracy"]; + } + + // A negative course value indicates that the course information is invalid. + // When courseAccuracy contains a negative number, the value in the course property is invalid. + // + // Relevant documentation: + // - https://developer.apple.com/documentation/corelocation/cllocation/1423832-course?language=objc + // - https://developer.apple.com/documentation/corelocation/cllocation/3524338-courseaccuracy?language=objc + double heading = location.course; + if (heading >= 0.0) { + if (@available(iOS 13.4, macOS 10.15.4, *)) { + double headingAccuracy = location.courseAccuracy; + if (headingAccuracy >= 0.0) { + [locationMap setObject:@(heading) forKey: @"heading"]; + [locationMap setObject:@(headingAccuracy) forKey: @"heading_accuracy"]; + } + } else { + [locationMap setObject:@(heading) forKey: @"heading"]; + } + } - if(@available(iOS 15.0, *)) { + if(@available(iOS 15.0, macOS 12.0, *)) { [locationMap setObject:@(location.sourceInformation.isSimulatedBySoftware) forKey: @"is_mocked"]; } diff --git a/geolocator_apple/pubspec.yaml b/geolocator_apple/pubspec.yaml index c02ebcdf8..529aea4d8 100644 --- a/geolocator_apple/pubspec.yaml +++ b/geolocator_apple/pubspec.yaml @@ -2,7 +2,7 @@ name: geolocator_apple description: Geolocation Apple plugin for Flutter. This plugin provides the Apple implementation for the geolocator. repository: https://github.com/baseflow/flutter-geolocator/tree/main/geolocator_apple issue_tracker: https://github.com/baseflow/flutter-geolocator/issues?q=is%3Aissue+is%3Aopen -version: 2.2.7 +version: 2.3.2 environment: sdk: ">=2.15.0 <4.0.0" @@ -22,8 +22,7 @@ flutter: dependencies: flutter: sdk: flutter - - geolocator_platform_interface: ^4.0.5 + geolocator_platform_interface: ^4.1.0 dev_dependencies: async: ^2.8.2 diff --git a/geolocator_apple/test/geolocator_apple_test.dart b/geolocator_apple/test/geolocator_apple_test.dart index acec7ce24..b727b1941 100644 --- a/geolocator_apple/test/geolocator_apple_test.dart +++ b/geolocator_apple/test/geolocator_apple_test.dart @@ -16,8 +16,10 @@ Position get mockPosition => Position( isUtc: true, ), altitude: 3000.0, + altitudeAccuracy: 0.0, accuracy: 0.0, heading: 0.0, + headingAccuracy: 0.0, speed: 0.0, speedAccuracy: 0.0, isMocked: false); diff --git a/geolocator_linux/CHANGELOG.md b/geolocator_linux/CHANGELOG.md index 76733beba..befc9aed9 100644 --- a/geolocator_linux/CHANGELOG.md +++ b/geolocator_linux/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.2.0 + +- Bumps `geolocator_platform_interface` dependency to `^4.1.0`. + ## 0.1.3 - Improves GNOME detection. diff --git a/geolocator_linux/example/pubspec.yaml b/geolocator_linux/example/pubspec.yaml index 43504d28d..d09a58e88 100644 --- a/geolocator_linux/example/pubspec.yaml +++ b/geolocator_linux/example/pubspec.yaml @@ -9,7 +9,7 @@ environment: sdk: ">=2.15.0 <3.0.0" dependencies: - baseflow_plugin_template: ^2.1.1 + baseflow_plugin_template: ^2.1.2 flutter: sdk: flutter @@ -41,9 +41,3 @@ dev_dependencies: flutter: uses-material-design: true - - assets: - - res/images/baseflow_logo_def_light-02.png - - res/images/poweredByBaseflowLogoLight@3x.png - - packages/baseflow_plugin_template/logo.png - - packages/baseflow_plugin_template/poweredByBaseflow.png diff --git a/geolocator_linux/lib/src/geoclue_x.dart b/geolocator_linux/lib/src/geoclue_x.dart index 9444a24b7..869b7880e 100644 --- a/geolocator_linux/lib/src/geoclue_x.dart +++ b/geolocator_linux/lib/src/geoclue_x.dart @@ -18,7 +18,9 @@ extension GeoCluePosition on GeoClueLocation { return Position( accuracy: accuracy, altitude: altitude ?? 0, + altitudeAccuracy: 0, heading: heading ?? 0, + headingAccuracy: 0, latitude: latitude, longitude: longitude, timestamp: timestamp, diff --git a/geolocator_linux/pubspec.yaml b/geolocator_linux/pubspec.yaml index bc1a5992e..66a7d7aae 100644 --- a/geolocator_linux/pubspec.yaml +++ b/geolocator_linux/pubspec.yaml @@ -3,10 +3,10 @@ description: Geolocation Linux plugin for Flutter. This plugin provides the Linux implementation for the geolocator. repository: https://github.com/baseflow/flutter-geolocator/tree/main/geolocator_linux issue_tracker: https://github.com/baseflow/flutter-geolocator/issues?q=is%3Aissue+is%3Aopen -version: 0.1.3 +version: 0.2.0 environment: - sdk: ">=2.15.0 <3.0.0" + sdk: '>=2.15.0 <4.0.0' flutter: ">=2.8.0" flutter: @@ -21,7 +21,7 @@ dependencies: flutter: sdk: flutter geoclue: ^0.1.1 - geolocator_platform_interface: ^4.0.0 + geolocator_platform_interface: ^4.1.0 gsettings: ^0.2.5 package_info_plus: ">=1.4.2 <5.0.0" diff --git a/geolocator_linux/test/geoclue_x_test.dart b/geolocator_linux/test/geoclue_x_test.dart index 3686a0bc2..f6897c620 100644 --- a/geolocator_linux/test/geoclue_x_test.dart +++ b/geolocator_linux/test/geoclue_x_test.dart @@ -49,7 +49,9 @@ final dummyLocation = GeoClueLocation( final dummyPosition = Position( accuracy: 1, altitude: 2, + altitudeAccuracy: 0, heading: 3, + headingAccuracy: 0, latitude: 4, longitude: 5, speed: 6, @@ -67,7 +69,9 @@ final dummyLocationNull = GeoClueLocation( final dummyPositionNull = Position( accuracy: 1, altitude: 0, + altitudeAccuracy: 0, heading: 0, + headingAccuracy: 0, latitude: 4, longitude: 5, speed: 0, diff --git a/geolocator_linux/test/geolocator_linux_test.dart b/geolocator_linux/test/geolocator_linux_test.dart index 55e34a350..a80b67d28 100644 --- a/geolocator_linux/test/geolocator_linux_test.dart +++ b/geolocator_linux/test/geolocator_linux_test.dart @@ -159,7 +159,9 @@ final dummyLocation = GeoClueLocation( final dummyPosition = Position( accuracy: 1, altitude: 2, + altitudeAccuracy: 0, heading: 3, + headingAccuracy: 0, latitude: 4, longitude: 5, speed: 6, diff --git a/geolocator_platform_interface/CHANGELOG.md b/geolocator_platform_interface/CHANGELOG.md index 5fbd9ea68..fb4ff66ba 100644 --- a/geolocator_platform_interface/CHANGELOG.md +++ b/geolocator_platform_interface/CHANGELOG.md @@ -1,3 +1,15 @@ +## 4.1.1 + +- Updates dependencies to latest versions to prevent conflicts with other packages. + +## 4.1.0 + +- Includes `altitudeAccuracy` and `headingAccuracy` in `Position`. + +## 4.0.8 + +- Updates documentation for `getCurrentPosition()` and `LocationAccuracy`, to clarify the behavior of location accuracy on Android devices. + ## 4.0.7 - Fixed a spelling error in docs. diff --git a/geolocator_platform_interface/lib/src/enums/location_accuracy.dart b/geolocator_platform_interface/lib/src/enums/location_accuracy.dart index c470aa2ae..526cce1e9 100644 --- a/geolocator_platform_interface/lib/src/enums/location_accuracy.dart +++ b/geolocator_platform_interface/lib/src/enums/location_accuracy.dart @@ -1,28 +1,49 @@ /// Represent the possible location accuracy values. enum LocationAccuracy { - /// Location is accurate within a distance of 3000m on iOS and 500m on Android + /// Location is accurate within a distance of 3000m on iOS and 500m on Android. + /// + /// On Android, corresponds to + /// [PRIORITY_PASSIVE](https://developers.google.com/android/reference/com/google/android/gms/location/Priority#public-static-final-int-priority_passive). lowest, - /// Location is accurate within a distance of 1000m on iOS and 500m on Android + /// Location is accurate within a distance of 1000m on iOS and 500m on Android. + /// + /// On Android, corresponds to + /// [PRIORITY_LOW_POWER](https://developers.google.com/android/reference/com/google/android/gms/location/Priority#public-static-final-int-priority_low_power). low, /// Location is accurate within a distance of 100m on iOS and between 100m and - /// 500m on Android + /// 500m on Android. + /// + /// On Android, corresponds to + /// [PRIORITY_BALANCED_POWER_ACCURACY](https://developers.google.com/android/reference/com/google/android/gms/location/Priority#public-static-final-int-priority_balanced_power_accuracy). medium, /// Location is accurate within a distance of 10m on iOS and between 0m and - /// 100m on Android + /// 100m on Android. + /// + /// On Android, corresponds to + /// [PRIORITY_HIGH_ACCURACY](https://developers.google.com/android/reference/com/google/android/gms/location/Priority#public-static-final-int-priority_high_accuracy). high, /// Location is accurate within a distance of ~0m on iOS and between 0m and - /// 100m on Android + /// 100m on Android. + /// + /// On Android, corresponds to + /// [PRIORITY_HIGH_ACCURACY](https://developers.google.com/android/reference/com/google/android/gms/location/Priority#public-static-final-int-priority_high_accuracy). best, /// Location accuracy is optimized for navigation on iOS and matches the - /// [LocationAccuracy.best] on Android + /// [LocationAccuracy.best] on Android. + /// + /// On Android, corresponds to + /// [PRIORITY_HIGH_ACCURACY](https://developers.google.com/android/reference/com/google/android/gms/location/Priority#public-static-final-int-priority_high_accuracy). bestForNavigation, /// Location accuracy is reduced for iOS 14+ devices, matches the /// [LocationAccuracy.lowest] on iOS 13 and below and all other platforms. + /// + /// On Android, corresponds to + /// [PRIORITY_PASSIVE](https://developers.google.com/android/reference/com/google/android/gms/location/Priority#public-static-final-int-priority_passive). reduced, } diff --git a/geolocator_platform_interface/lib/src/geolocator_platform_interface.dart b/geolocator_platform_interface/lib/src/geolocator_platform_interface.dart index ebb223bbe..dd3499ee3 100644 --- a/geolocator_platform_interface/lib/src/geolocator_platform_interface.dart +++ b/geolocator_platform_interface/lib/src/geolocator_platform_interface.dart @@ -87,27 +87,39 @@ abstract class GeolocatorPlatform extends PlatformInterface { ); } - /// Returns the current position taking the supplied [desiredAccuracy] into - /// account. + /// Returns the current position. /// - /// Calling the `getCurrentPosition` method will request the platform to - /// obtain a location fix, depending on the availability of different location - /// services this can take several seconds. The recommended use would be to - /// call the `getLastKnownPosition` method to receive a cached position and - /// update it with the result of the `getCurrentPosition` method. + /// You can control the settings used for retrieving the location by supplying + /// [locationSettings]. /// - /// On Android you can force the use of the Android LocationManager instead of - /// the FusedLocationProvider by setting the [forceLocationManager] - /// parameter of [LocationSettings] to true. The [timeLimit] parameter of - /// [LocationSettings] allows you to specify a timeout interval (by default no - /// time limit is configured). + /// Calling the [getCurrentPosition] method will request the platform to + /// obtain a location fix. Depending on the availability of different location + /// services, this can take several seconds. The recommended use would be to + /// call the [getLastKnownPosition] method to receive a cached position and + /// update it with the result of the [getCurrentPosition] method. /// - /// Throws a [TimeoutException] when no location is received within the - /// supplied [timeLimit] duration. - /// Throws a [PermissionDeniedException] when trying to request the device's - /// location when the user denied access. - /// Throws a [LocationServiceDisabledException] when the user allowed access, - /// but the location services of the device are disabled. + /// **Note**: On Android, when setting the location accuracy, the location + /// *accuracy* is interpreted as + /// [location *priority*](https://developers.google.com/android/reference/com/google/android/gms/location/Priority#constants). + /// The interpretation works as follows: + /// + /// [LocationAccuracy.lowest] -> [PRIORITY_PASSIVE](https://developers.google.com/android/reference/com/google/android/gms/location/Priority#public-static-final-int-priority_passive): + /// Ensures that no extra power will be used to derive locations. This + /// enforces that the request will act as a passive listener that will only + /// receive "free" locations calculated on behalf of other clients, and no + /// locations will be calculated on behalf of only this request. + /// + /// [LocationAccuracy.low] -> [PRIORITY_LOW_POWER](https://developers.google.com/android/reference/com/google/android/gms/location/Priority#public-static-final-int-priority_low_power): + /// Requests a tradeoff that favors low power usage at the possible expense of + /// location accuracy. + /// + /// [LocationAccuracy.medium] -> [PRIORITY_BALANCED_POWER_ACCURACY](https://developers.google.com/android/reference/com/google/android/gms/location/Priority#public-static-final-int-priority_balanced_power_accuracy): + /// Requests a tradeoff that is balanced between location accuracy and power + /// usage. + /// + /// [LocationAccuracy.high]+ -> [PRIORITY_HIGH_ACCURACY](https://developers.google.com/android/reference/com/google/android/gms/location/Priority#public-static-final-int-priority_high_accuracy): + /// Requests a tradeoff that favors highly accurate locations at the possible + /// expense of additional power usage. Future getCurrentPosition({ LocationSettings? locationSettings, }) { diff --git a/geolocator_platform_interface/lib/src/models/position.dart b/geolocator_platform_interface/lib/src/models/position.dart index 2c93b979c..d6a491416 100644 --- a/geolocator_platform_interface/lib/src/models/position.dart +++ b/geolocator_platform_interface/lib/src/models/position.dart @@ -12,7 +12,9 @@ class Position { required this.timestamp, required this.accuracy, required this.altitude, + required this.altitudeAccuracy, required this.heading, + required this.headingAccuracy, required this.speed, required this.speedAccuracy, this.floor, @@ -36,6 +38,12 @@ class Position { /// value is 0.0. final double altitude; + /// The estimated vertical accuracy of the position in meters. + /// + /// The accuracy is not available on all devices. In these cases the value is + /// 0.0. + final double altitudeAccuracy; + /// The estimated horizontal accuracy of the position in meters. /// /// The accuracy is not available on all devices. In these cases the value is @@ -48,6 +56,12 @@ class Position { /// 0.0. final double heading; + /// The estimated heading accuracy of the position in degrees. + /// + /// The heading accuracy is not available on all devices. In these cases the + /// value is 0.0. + final double headingAccuracy; + /// The floor specifies the floor of the building on which the device is /// located. /// @@ -79,7 +93,9 @@ class Position { var areEqual = other is Position && other.accuracy == accuracy && other.altitude == altitude && + other.altitudeAccuracy == altitudeAccuracy && other.heading == heading && + other.headingAccuracy == headingAccuracy && other.latitude == latitude && other.longitude == longitude && other.floor == floor && @@ -95,7 +111,9 @@ class Position { int get hashCode => accuracy.hashCode ^ altitude.hashCode ^ + altitudeAccuracy.hashCode ^ heading.hashCode ^ + headingAccuracy.hashCode ^ latitude.hashCode ^ longitude.hashCode ^ floor.hashCode ^ @@ -132,8 +150,10 @@ class Position { longitude: positionMap['longitude'], timestamp: timestamp, altitude: positionMap['altitude'] ?? 0.0, + altitudeAccuracy: positionMap['altitude_accuracy'] ?? 0.0, accuracy: positionMap['accuracy'] ?? 0.0, heading: positionMap['heading'] ?? 0.0, + headingAccuracy: positionMap['heading_accuracy'] ?? 0.0, floor: positionMap['floor'], speed: positionMap['speed'] ?? 0.0, speedAccuracy: positionMap['speed_accuracy'] ?? 0.0, @@ -149,8 +169,10 @@ class Position { 'timestamp': timestamp.millisecondsSinceEpoch, 'accuracy': accuracy, 'altitude': altitude, + 'altitude_accuracy': altitudeAccuracy, 'floor': floor, 'heading': heading, + 'heading_accuracy': headingAccuracy, 'speed': speed, 'speed_accuracy': speedAccuracy, 'is_mocked': isMocked, diff --git a/geolocator_platform_interface/pubspec.yaml b/geolocator_platform_interface/pubspec.yaml index 007968daa..82489c082 100644 --- a/geolocator_platform_interface/pubspec.yaml +++ b/geolocator_platform_interface/pubspec.yaml @@ -3,23 +3,23 @@ description: A common platform interface for the geolocator plugin. repository: https://github.com/baseflow/flutter-geolocator/tree/main/geolocator_platform_interface # NOTE: We strongly prefer non-breaking changes, even at the expense of a # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes -version: 4.0.7 +version: 4.1.1 dependencies: flutter: sdk: flutter - plugin_platform_interface: ^2.1.1 - vector_math: ^2.1.0 - meta: ^1.3.0 + plugin_platform_interface: ^2.1.6 + vector_math: ^2.1.4 + meta: ^1.9.1 dev_dependencies: - async: ^2.8.1 + async: ^2.11.0 flutter_test: sdk: flutter - flutter_lints: ^1.0.4 - mockito: ^5.0.0-nullsafety.7 + flutter_lints: ^2.0.3 + mockito: ^5.4.2 environment: - sdk: ">=2.15.0 <3.0.0" + sdk: ">=2.15.0 <4.0.0" flutter: ">=2.8.0" diff --git a/geolocator_platform_interface/test/src/implementations/event_channel_mock.dart b/geolocator_platform_interface/test/src/implementations/event_channel_mock.dart index 8e21f1834..afe77e6a9 100644 --- a/geolocator_platform_interface/test/src/implementations/event_channel_mock.dart +++ b/geolocator_platform_interface/test/src/implementations/event_channel_mock.dart @@ -14,7 +14,7 @@ class EventChannelMock { required String channelName, required this.stream, }) : _methodChannel = MethodChannel(channelName) { - TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(_methodChannel, _handler); } @@ -76,11 +76,7 @@ class EventChannelMock { } void _sendEnvelope(ByteData? envelope) { - if (TestDefaultBinaryMessengerBinding.instance == null) { - return; - } - - TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .handlePlatformMessage( _methodChannel.name, envelope, diff --git a/geolocator_platform_interface/test/src/implementations/method_channel_geolocator_test.dart b/geolocator_platform_interface/test/src/implementations/method_channel_geolocator_test.dart index 964db9118..b313a0ce3 100644 --- a/geolocator_platform_interface/test/src/implementations/method_channel_geolocator_test.dart +++ b/geolocator_platform_interface/test/src/implementations/method_channel_geolocator_test.dart @@ -17,8 +17,10 @@ Position get mockPosition => Position( isUtc: true, ), altitude: 3000.0, + altitudeAccuracy: 2.0, accuracy: 0.0, heading: 0.0, + headingAccuracy: 0.0, speed: 0.0, speedAccuracy: 0.0, isMocked: false); @@ -33,7 +35,6 @@ void main() { group('checkPermission: When checking for permission', () { test( - // ignore: lines_longer_than_80_chars 'Should receive whenInUse if permission is granted when App is in use', () async { // Arrange @@ -234,7 +235,7 @@ void main() { expect(locationAccuracy, LocationAccuracyStatus.reduced); }); - test('Should receive reduced accuracy if Location Accuracy is reduced', + test('Should receive reduced accuracy if Location Accuracy is precise', () async { // Arrange MethodChannelMock( @@ -254,7 +255,6 @@ void main() { group('requestPermission: When requesting for permission', () { test( - // ignore: lines_longer_than_80_chars 'Should receive whenInUse if permission is granted when App is in use', () async { // Arrange @@ -608,7 +608,6 @@ void main() { }); test( - // ignore: lines_longer_than_80_chars 'Should throw a location service disabled exception if location services are disabled', () async { // Arrange @@ -727,9 +726,7 @@ void main() { streamSubscription = null; }); - test( - // ignore: lines_longer_than_80_chars - 'Should correctly handle done event', () async { + test('Should correctly handle done event', () async { // Arrange final completer = Completer(); completer.future.timeout(const Duration(milliseconds: 50), @@ -755,7 +752,6 @@ void main() { }); test( - // ignore: lines_longer_than_80_chars 'Should receive a stream with position updates if permissions are granted', () async { // Arrange @@ -785,9 +781,7 @@ void main() { await streamController.close(); }); - test( - // ignore: lines_longer_than_80_chars - 'Should continue listening to the stream when exception is thrown ', + test('Should continue listening to the stream when exception is thrown ', () async { // Arrange final streamController = @@ -828,7 +822,6 @@ void main() { }); test( - // ignore: lines_longer_than_80_chars 'Should receive a permission denied exception if permission is denied', () async { // Arrange @@ -866,7 +859,6 @@ void main() { }); test( - // ignore: lines_longer_than_80_chars 'Should receive a location service disabled exception if location service is disabled', () async { // Arrange @@ -899,9 +891,8 @@ void main() { streamController.close(); }); - test( - // ignore: lines_longer_than_80_chars - 'Should receive a already subscribed exception', () async { + test('Should receive a permission request in progress exception', + () async { // Arrange final streamController = StreamController.broadcast(); @@ -932,9 +923,7 @@ void main() { streamController.close(); }); - test( - // ignore: lines_longer_than_80_chars - 'Should receive a already subscribed exception', () async { + test('Should receive an already subscribed exception', () async { // Arrange final streamController = StreamController.broadcast(); @@ -965,9 +954,7 @@ void main() { streamController.close(); }); - test( - // ignore: lines_longer_than_80_chars - 'Should receive a position update exception', () async { + test('Should receive a position update exception', () async { // Arrange final streamController = StreamController.broadcast(); @@ -1077,7 +1064,6 @@ void main() { }); group( - // ignore: lines_longer_than_80_chars 'getServiceStream: When requesting a stream of location service status updates', () { group('And requesting for location service status updates multiple times', @@ -1095,7 +1081,6 @@ void main() { }); test( - // ignore: lines_longer_than_80_chars 'Should receive a stream with location service updates if permissions are granted', () async { // Arrange @@ -1122,9 +1107,7 @@ void main() { await streamController.close(); }); - test( - // ignore: lines_longer_than_80_chars - 'Should receive an exception if android activity is missing', + test('Should receive an exception if android activity is missing', () async { // Arrange final streamController = diff --git a/geolocator_platform_interface/test/src/implementations/method_channel_mock.dart b/geolocator_platform_interface/test/src/implementations/method_channel_mock.dart index 3612b295c..12ccc0792 100644 --- a/geolocator_platform_interface/test/src/implementations/method_channel_mock.dart +++ b/geolocator_platform_interface/test/src/implementations/method_channel_mock.dart @@ -14,7 +14,7 @@ class MethodChannelMock { this.delay = Duration.zero, this.result, }) : methodChannel = MethodChannel(channelName) { - TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(methodChannel, _handler); } diff --git a/geolocator_platform_interface/test/src/models/position_test.dart b/geolocator_platform_interface/test/src/models/position_test.dart index e18b195fe..265429d70 100644 --- a/geolocator_platform_interface/test/src/models/position_test.dart +++ b/geolocator_platform_interface/test/src/models/position_test.dart @@ -12,7 +12,9 @@ void main() { timestamp: DateTime.fromMillisecondsSinceEpoch(0), accuracy: 0, altitude: 0, + altitudeAccuracy: 0, heading: 0, + headingAccuracy: 0, speed: 0, speedAccuracy: 0, isMocked: false, @@ -23,7 +25,9 @@ void main() { timestamp: DateTime.fromMillisecondsSinceEpoch(0), accuracy: 0, altitude: 0, + altitudeAccuracy: 0, heading: 0, + headingAccuracy: 0, speed: 0, speedAccuracy: 0, isMocked: false, @@ -45,7 +49,9 @@ void main() { timestamp: DateTime.fromMillisecondsSinceEpoch(0), accuracy: 0, altitude: 0, + altitudeAccuracy: 0, heading: 0, + headingAccuracy: 0, speed: 0, speedAccuracy: 0, isMocked: false, @@ -56,7 +62,9 @@ void main() { timestamp: DateTime.fromMillisecondsSinceEpoch(0), accuracy: 0, altitude: 0, + altitudeAccuracy: 0, heading: 0, + headingAccuracy: 0, speed: 0, speedAccuracy: 0, isMocked: false, @@ -78,7 +86,9 @@ void main() { timestamp: DateTime.fromMillisecondsSinceEpoch(0), accuracy: 0, altitude: 0, + altitudeAccuracy: 0, heading: 0, + headingAccuracy: 0, speed: 0, speedAccuracy: 0, isMocked: false, @@ -89,7 +99,9 @@ void main() { timestamp: DateTime.fromMillisecondsSinceEpoch(0), accuracy: 0, altitude: 0, + altitudeAccuracy: 0, heading: 0, + headingAccuracy: 0, speed: 0, speedAccuracy: 0, isMocked: false, @@ -111,7 +123,9 @@ void main() { timestamp: DateTime.fromMillisecondsSinceEpoch(0), accuracy: 0, altitude: 0, + altitudeAccuracy: 0, heading: 0, + headingAccuracy: 0, speed: 0, speedAccuracy: 0, isMocked: false, @@ -122,7 +136,9 @@ void main() { timestamp: DateTime.fromMillisecondsSinceEpoch(1), accuracy: 0, altitude: 0, + altitudeAccuracy: 0, heading: 0, + headingAccuracy: 0, speed: 0, speedAccuracy: 0, isMocked: false, @@ -144,7 +160,9 @@ void main() { timestamp: DateTime.fromMillisecondsSinceEpoch(0), accuracy: 0, altitude: 0, + altitudeAccuracy: 0, heading: 0, + headingAccuracy: 0, speed: 0, speedAccuracy: 0, isMocked: false, @@ -155,7 +173,9 @@ void main() { timestamp: DateTime.fromMillisecondsSinceEpoch(0), accuracy: 1, altitude: 0, + altitudeAccuracy: 0, heading: 0, + headingAccuracy: 0, speed: 0, speedAccuracy: 0, isMocked: false, @@ -177,7 +197,9 @@ void main() { timestamp: DateTime.fromMillisecondsSinceEpoch(0), accuracy: 0, altitude: 0, + altitudeAccuracy: 0, heading: 0, + headingAccuracy: 0, speed: 0, speedAccuracy: 0, isMocked: false, @@ -188,7 +210,47 @@ void main() { timestamp: DateTime.fromMillisecondsSinceEpoch(0), accuracy: 0, altitude: 1, + altitudeAccuracy: 0, heading: 0, + headingAccuracy: 0, + speed: 0, + speedAccuracy: 0, + isMocked: false, + ); + + // Act & Assert + expect( + firstPosition.hashCode != secondPosition.hashCode, + true, + ); + }); + + test( + 'hashCode should not match when the altitudeAccuracy property is different', + () { + // Arrange + final firstPosition = Position( + longitude: 0, + latitude: 0, + timestamp: DateTime.fromMillisecondsSinceEpoch(0), + accuracy: 0, + altitude: 0, + altitudeAccuracy: 0, + heading: 0, + headingAccuracy: 0, + speed: 0, + speedAccuracy: 0, + isMocked: false, + ); + final secondPosition = Position( + longitude: 0, + latitude: 0, + timestamp: DateTime.fromMillisecondsSinceEpoch(0), + accuracy: 0, + altitude: 0, + altitudeAccuracy: 1, + heading: 0, + headingAccuracy: 0, speed: 0, speedAccuracy: 0, isMocked: false, @@ -210,7 +272,9 @@ void main() { timestamp: DateTime.fromMillisecondsSinceEpoch(0), accuracy: 0, altitude: 0, + altitudeAccuracy: 0, heading: 0, + headingAccuracy: 0, speed: 0, speedAccuracy: 0, isMocked: false, @@ -221,7 +285,47 @@ void main() { timestamp: DateTime.fromMillisecondsSinceEpoch(0), accuracy: 0, altitude: 0, + altitudeAccuracy: 0, heading: 1, + headingAccuracy: 0, + speed: 0, + speedAccuracy: 0, + isMocked: false, + ); + + // Act & Assert + expect( + firstPosition.hashCode != secondPosition.hashCode, + true, + ); + }); + + test( + 'hashCode should not match when the headingAccuracy property is different', + () { + // Arrange + final firstPosition = Position( + longitude: 0, + latitude: 0, + timestamp: DateTime.fromMillisecondsSinceEpoch(0), + accuracy: 0, + altitude: 0, + altitudeAccuracy: 0, + heading: 0, + headingAccuracy: 0, + speed: 0, + speedAccuracy: 0, + isMocked: false, + ); + final secondPosition = Position( + longitude: 0, + latitude: 0, + timestamp: DateTime.fromMillisecondsSinceEpoch(0), + accuracy: 0, + altitude: 0, + altitudeAccuracy: 0, + heading: 0, + headingAccuracy: 1, speed: 0, speedAccuracy: 0, isMocked: false, @@ -242,7 +346,9 @@ void main() { timestamp: DateTime.fromMillisecondsSinceEpoch(0), accuracy: 0, altitude: 0, + altitudeAccuracy: 0, heading: 0, + headingAccuracy: 0, speed: 0, speedAccuracy: 0, isMocked: false, @@ -253,7 +359,9 @@ void main() { timestamp: DateTime.fromMillisecondsSinceEpoch(0), accuracy: 0, altitude: 0, + altitudeAccuracy: 0, heading: 0, + headingAccuracy: 0, speed: 1, speedAccuracy: 0, isMocked: false, @@ -267,7 +375,6 @@ void main() { }); test( - // ignore: lines_longer_than_80_chars 'hashCode should not match when the speedAccuracy property is different', () { // Arrange @@ -277,7 +384,9 @@ void main() { timestamp: DateTime.fromMillisecondsSinceEpoch(0), accuracy: 0, altitude: 0, + altitudeAccuracy: 0, heading: 0, + headingAccuracy: 0, speed: 0, speedAccuracy: 0, isMocked: false, @@ -288,7 +397,9 @@ void main() { timestamp: DateTime.fromMillisecondsSinceEpoch(0), accuracy: 0, altitude: 0, + altitudeAccuracy: 0, heading: 0, + headingAccuracy: 0, speed: 0, speedAccuracy: 1, isMocked: false, @@ -301,9 +412,7 @@ void main() { ); }); - test( - // ignore: lines_longer_than_80_chars - 'hashCode should not match when the speedAccuracy property is different', + test('hashCode should not match when the isMocked property is different', () { // Arrange final firstPosition = Position( @@ -312,7 +421,9 @@ void main() { timestamp: DateTime.fromMillisecondsSinceEpoch(0), accuracy: 0, altitude: 0, + altitudeAccuracy: 0, heading: 0, + headingAccuracy: 0, speed: 0, speedAccuracy: 0, isMocked: false, @@ -323,7 +434,9 @@ void main() { timestamp: DateTime.fromMillisecondsSinceEpoch(0), accuracy: 0, altitude: 0, + altitudeAccuracy: 0, heading: 0, + headingAccuracy: 0, speed: 0, speedAccuracy: 0, isMocked: true, @@ -344,7 +457,9 @@ void main() { timestamp: DateTime.fromMillisecondsSinceEpoch(0), accuracy: 0, altitude: 0, + altitudeAccuracy: 0, heading: 0, + headingAccuracy: 0, floor: 0, speed: 0, speedAccuracy: 0, @@ -356,7 +471,9 @@ void main() { timestamp: DateTime.fromMillisecondsSinceEpoch(0), accuracy: 0, altitude: 0, + altitudeAccuracy: 0, heading: 0, + headingAccuracy: 0, floor: 1, speed: 0, speedAccuracy: 0, @@ -373,7 +490,6 @@ void main() { group('fromMap tests:', () { test( - // ignore: lines_longer_than_80_chars 'fromMap should throw argument error when map does not contain latitude', () { // Arrange @@ -386,7 +502,6 @@ void main() { }); test( - // ignore: lines_longer_than_80_chars 'fromMap should throw argument error when map does not contain latitude', () { // Arrange @@ -408,7 +523,9 @@ void main() { timestamp: DateTime.fromMillisecondsSinceEpoch(0), accuracy: 0, altitude: 0, + altitudeAccuracy: 0, heading: 0, + headingAccuracy: 0, speed: 0, speedAccuracy: 0, isMocked: false, diff --git a/geolocator_web/CHANGELOG.md b/geolocator_web/CHANGELOG.md index 2e1cf2903..23cd578a8 100644 --- a/geolocator_web/CHANGELOG.md +++ b/geolocator_web/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.2.0 + +- Exposes altitude accuracy field in `Position` object. + ## 2.1.7 - Mark `geolocator_web` as implementation of `geolocator` diff --git a/geolocator_web/example/lib/main.dart b/geolocator_web/example/lib/main.dart index af6086ad2..8e058ed2e 100644 --- a/geolocator_web/example/lib/main.dart +++ b/geolocator_web/example/lib/main.dart @@ -52,7 +52,7 @@ class _GeolocatorWidgetState extends State { ); return Scaffold( - backgroundColor: Theme.of(context).backgroundColor, + backgroundColor: Theme.of(context).colorScheme.background, body: ListView.builder( itemCount: _positionItems.length, itemBuilder: (context, index) { diff --git a/geolocator_web/example/pubspec.yaml b/geolocator_web/example/pubspec.yaml index 8fee27fd8..cc62c24be 100644 --- a/geolocator_web/example/pubspec.yaml +++ b/geolocator_web/example/pubspec.yaml @@ -9,7 +9,7 @@ environment: sdk: ">=2.15.0-0 <3.0.0" dependencies: - baseflow_plugin_template: ^2.1.1 + baseflow_plugin_template: ^2.1.2 flutter: sdk: flutter @@ -41,9 +41,3 @@ dev_dependencies: flutter: uses-material-design: true - - assets: - - res/images/baseflow_logo_def_light-02.png - - res/images/poweredByBaseflowLogoLight@3x.png - - packages/baseflow_plugin_template/logo.png - - packages/baseflow_plugin_template/poweredByBaseflow.png diff --git a/geolocator_web/lib/src/utils.dart b/geolocator_web/lib/src/utils.dart index ebd86aca5..cd50aee5a 100644 --- a/geolocator_web/lib/src/utils.dart +++ b/geolocator_web/lib/src/utils.dart @@ -18,8 +18,10 @@ Position toPosition(html.Geoposition webPosition) { ? DateTime.fromMillisecondsSinceEpoch(webPosition.timestamp!) : DateTime.now(), altitude: coords.altitude as double? ?? 0.0, + altitudeAccuracy: coords.altitudeAccuracy as double? ?? 0.0, accuracy: coords.accuracy as double? ?? 0.0, heading: coords.heading as double? ?? 0.0, + headingAccuracy: 0.0, floor: null, speed: coords.speed as double? ?? 0.0, speedAccuracy: 0.0, diff --git a/geolocator_web/pubspec.yaml b/geolocator_web/pubspec.yaml index 8c77c44cc..973e8b04f 100644 --- a/geolocator_web/pubspec.yaml +++ b/geolocator_web/pubspec.yaml @@ -2,7 +2,7 @@ name: geolocator_web description: Official web implementation of the geolocator plugin. repository: https://github.com/baseflow/flutter-geolocator/tree/main/geolocator_web issue_tracker: https://github.com/baseflow/flutter-geolocator/issues?q=is%3Aissue+is%3Aopen -version: 2.1.7 +version: 2.2.0 flutter: plugin: @@ -17,7 +17,7 @@ dependencies: sdk: flutter flutter_web_plugins: sdk: flutter - geolocator_platform_interface: ^4.0.1 + geolocator_platform_interface: ^4.1.0 dev_dependencies: flutter_test: @@ -26,5 +26,5 @@ dev_dependencies: mockito: ^5.0.0 environment: - sdk: '>=2.15.0 <3.0.0' + sdk: '>=2.15.0 <4.0.0' flutter: ">=2.8.0" diff --git a/geolocator_web/test/geolocator_web_test.dart b/geolocator_web/test/geolocator_web_test.dart index 48e81ba7d..dcc5ef044 100644 --- a/geolocator_web/test/geolocator_web_test.dart +++ b/geolocator_web/test/geolocator_web_test.dart @@ -15,8 +15,10 @@ List get mockPositions => List.of(() sync* { isUtc: true, ), altitude: 3000.0, + altitudeAccuracy: 0.0, accuracy: 0.0, heading: 0.0, + headingAccuracy: 0.0, speed: 0.0, speedAccuracy: 0.0); } @@ -150,8 +152,10 @@ void main() { isUtc: true, ), altitude: 3000.0, + altitudeAccuracy: 0.0, accuracy: 0.0, heading: 0.0, + headingAccuracy: 0.0, speed: 0.0, speedAccuracy: 0.0); } diff --git a/geolocator_windows/CHANGELOG.md b/geolocator_windows/CHANGELOG.md index da102e859..37636a1b4 100644 --- a/geolocator_windows/CHANGELOG.md +++ b/geolocator_windows/CHANGELOG.md @@ -1,3 +1,11 @@ +## 0.2.2 + +* Fixes crash under Windows when getCurrentPosition method is called. (#1240) + +## 0.2.1 + +* Exposes altitude accuracy to the `Position` class. + ## 0.2.0 * **BREAKING CHANGE:** Synchronizes the default values of `Position.altitude`, `Position.heading` and `Position.speed` with the other platforms and return 0.0 if the value is not known. @@ -20,4 +28,4 @@ if "Let apps access your location" toggle option is switched ON from OFF. ## 0.1.0 -* Adds an initial implementation of Windows support for the geolocator plugin. \ No newline at end of file +* Adds an initial implementation of Windows support for the geolocator plugin. diff --git a/geolocator_windows/example/pubspec.yaml b/geolocator_windows/example/pubspec.yaml index bc6fec21a..90fa2905c 100644 --- a/geolocator_windows/example/pubspec.yaml +++ b/geolocator_windows/example/pubspec.yaml @@ -40,5 +40,4 @@ dev_dependencies: # The following section is specific to Flutter. flutter: - uses-material-design: true diff --git a/geolocator_windows/pubspec.yaml b/geolocator_windows/pubspec.yaml index 2ac6256fa..c914ab96f 100644 --- a/geolocator_windows/pubspec.yaml +++ b/geolocator_windows/pubspec.yaml @@ -2,7 +2,7 @@ name: geolocator_windows description: Geolocation Windows plugin for Flutter. This plugin provides the Windows implementation for the geolocator. repository: https://github.com/baseflow/flutter-geolocators issue_tracker: https://github.com/baseflow/flutter-geolocator/issues?q=is%3Aissue+is%3Aopen -version: 0.2.0 +version: 0.2.2 environment: sdk: ">=2.15.0 <4.0.0" @@ -18,8 +18,7 @@ flutter: dependencies: flutter: sdk: flutter - - geolocator_platform_interface: ^4.0.0 + geolocator_platform_interface: ^4.1.0 dev_dependencies: flutter_test: diff --git a/geolocator_windows/windows/geolocator_enums.h b/geolocator_windows/windows/geolocator_enums.h index d45bcc90d..dfb9e146a 100644 --- a/geolocator_windows/windows/geolocator_enums.h +++ b/geolocator_windows/windows/geolocator_enums.h @@ -1,7 +1,9 @@ namespace geolocator_plugin { enum ErrorCode { - PermissionDefinitionsNotFound + PermissionDefinitionsNotFound, + OperationCanceled, + UnknownError }; enum LocationPermission { @@ -31,4 +33,4 @@ enum ServiceStatus { Enabled }; -} // namespace geolocator_plugin \ No newline at end of file +} // namespace geolocator_plugin diff --git a/geolocator_windows/windows/geolocator_plugin.cpp b/geolocator_windows/windows/geolocator_plugin.cpp index b504ab640..7ac507af0 100644 --- a/geolocator_windows/windows/geolocator_plugin.cpp +++ b/geolocator_windows/windows/geolocator_plugin.cpp @@ -25,8 +25,12 @@ std::string ErrorCodeToString(ErrorCode errorCode) { switch (errorCode) { case ErrorCode::PermissionDefinitionsNotFound: return "PERMISSION_DEFINITIONS_NOT_FOUND"; + case ErrorCode::OperationCanceled: + return "OPERATION_CANCELED"; + case ErrorCode::UnknownError: + return "UNKNOWN_ERROR"; default: - return ""; + throw std::logic_error("unexcepted value" + static_cast(errorCode)); } } @@ -146,8 +150,13 @@ void GeolocatorPlugin::OnCheckPermission(std::unique_ptr> result) RequestAccessAsync(std::move(result)); } +bool isLocationStatusValid (const PositionStatus& status) { + return status != PositionStatus::Disabled + && status != PositionStatus::NotAvailable; +} + void GeolocatorPlugin::OnIsLocationServiceEnabled(std::unique_ptr> result) { - result->Success(EncodableValue(geolocator.LocationStatus() != PositionStatus::NotAvailable)); + result->Success(EncodableValue(isLocationStatusValid(geolocator.LocationStatus()))); } void GeolocatorPlugin::OnRequestPermission(std::unique_ptr> result) { @@ -156,8 +165,18 @@ void GeolocatorPlugin::OnRequestPermission(std::unique_ptr> resul winrt::fire_and_forget GeolocatorPlugin::OnGetLastKnownPosition(const MethodCall<>& method_call, std::unique_ptr> result) { - auto location = co_await geolocator.GetGeopositionAsync(std::chrono::hours(1), std::chrono::milliseconds::zero()); - result->Success(LocationToEncodableMap(location)); + try { + auto location = co_await geolocator.GetGeopositionAsync(std::chrono::hours(1), std::chrono::milliseconds::zero()); + result->Success(LocationToEncodableMap(location)); + } + catch (hresult_canceled const& error) { + result->Error(ErrorCodeToString(ErrorCode::OperationCanceled), + to_string(error.message())); + } + catch (hresult_error const& error) { + result->Error(ErrorCodeToString(ErrorCode::UnknownError), + to_string(error.message())); + } } void GeolocatorPlugin::GetLocationAccuracy(std::unique_ptr> result) { @@ -169,9 +188,18 @@ void GeolocatorPlugin::GetLocationAccuracy(std::unique_ptr> resul winrt::fire_and_forget GeolocatorPlugin::OnGetCurrentPosition(const MethodCall<>& method_call, std::unique_ptr> result) { - - auto location = co_await geolocator.GetGeopositionAsync(); - result->Success(LocationToEncodableMap(location)); + try { + auto location = co_await geolocator.GetGeopositionAsync(); + result->Success(LocationToEncodableMap(location)); + } + catch (hresult_canceled const& error) { + result->Error(ErrorCodeToString(ErrorCode::OperationCanceled), + to_string(error.message())); + } + catch (hresult_error const& error) { + result->Error(ErrorCodeToString(ErrorCode::UnknownError), + to_string(error.message())); + } } std::unique_ptr> GeolocatorPlugin::OnListen( @@ -257,6 +285,11 @@ EncodableMap GeolocatorPlugin::LocationToEncodableMap(Geoposition const& locatio : 0; position.insert(std::make_pair(EncodableValue("altitude"), EncodableValue(altitude))); + double altitudeAccuracy = location.Coordinate().AltitudeAccuracy() != nullptr && !std::isnan(location.Coordinate().AltitudeAccuracy().GetDouble()) + ? location.Coordinate().AltitudeAccuracy().GetDouble() + : 0; + position.insert(std::make_pair(EncodableValue("altitude_accuracy"), EncodableValue(altitudeAccuracy))); + position.insert(std::make_pair(EncodableValue("accuracy"), EncodableValue(location.Coordinate().Accuracy()))); double heading = location.Coordinate().Heading() != nullptr && !std::isnan(location.Coordinate().Heading().GetDouble())