LCOV - code coverage report
Current view: top level - src/implementations - method_channel_geolocator.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 95 95 100.0 %
Date: 2021-06-11 15:23:14 Functions: 0 0 -

          Line data    Source code
       1             : import 'dart:async';
       2             : 
       3             : import 'package:flutter/services.dart';
       4             : 
       5             : import '../../geolocator_platform_interface.dart';
       6             : import '../enums/enums.dart';
       7             : import '../errors/errors.dart';
       8             : import '../extensions/extensions.dart';
       9             : import '../geolocator_platform_interface.dart';
      10             : import '../models/location_options.dart';
      11             : import '../models/position.dart';
      12             : 
      13             : /// An implementation of [GeolocatorPlatform] that uses method channels.
      14             : class MethodChannelGeolocator extends GeolocatorPlatform {
      15             :   /// The method channel used to interact with the native platform.
      16             :   static const _methodChannel =
      17             :       MethodChannel('flutter.baseflow.com/geolocator');
      18             : 
      19             :   /// The event channel used to receive [Position] updates from the native
      20             :   /// platform.
      21             :   static const _eventChannel =
      22             :       EventChannel('flutter.baseflow.com/geolocator_updates');
      23             : 
      24             :   /// The event channel used to receive [LocationServiceStatus] updates from the
      25             :   /// native platform.
      26             :   static const _serviceStatusEventChannel =
      27             :       EventChannel('flutter.baseflow.com/geolocator_service_updates');
      28             : 
      29             :   /// On Android devices you can set [forceAndroidLocationManager]
      30             :   /// to true to force the plugin to use the [LocationManager] to determine the
      31             :   /// position instead of the [FusedLocationProviderClient]. On iOS this is
      32             :   /// ignored.
      33             :   bool forceAndroidLocationManager = false;
      34             : 
      35             :   Stream<Position>? _positionStream;
      36             :   Stream<ServiceStatus>? _serviceStatusStream;
      37             : 
      38             :   @override
      39           1 :   Future<LocationPermission> checkPermission() async {
      40             :     try {
      41             :       // ignore: omit_local_variable_types
      42             :       final int permission =
      43           2 :           await _methodChannel.invokeMethod('checkPermission');
      44             : 
      45           1 :       return permission.toLocationPermission();
      46           1 :     } on PlatformException catch (e) {
      47           1 :       _handlePlatformException(e);
      48             : 
      49             :       rethrow;
      50             :     }
      51             :   }
      52             : 
      53             :   @override
      54           1 :   Future<LocationPermission> requestPermission() async {
      55             :     try {
      56             :       // ignore: omit_local_variable_types
      57             :       final int permission =
      58           2 :           await _methodChannel.invokeMethod('requestPermission');
      59             : 
      60           1 :       return permission.toLocationPermission();
      61           1 :     } on PlatformException catch (e) {
      62           1 :       _handlePlatformException(e);
      63             : 
      64             :       rethrow;
      65             :     }
      66             :   }
      67             : 
      68             :   @override
      69           1 :   Future<bool> isLocationServiceEnabled() async => _methodChannel
      70           1 :       .invokeMethod<bool>('isLocationServiceEnabled')
      71           2 :       .then((value) => value ?? false);
      72             : 
      73             :   @override
      74           1 :   Future<Position?> getLastKnownPosition({
      75             :     bool forceAndroidLocationManager = false,
      76             :   }) async {
      77             :     try {
      78           1 :       final parameters = <String, dynamic>{
      79             :         'forceAndroidLocationManager': forceAndroidLocationManager,
      80             :       };
      81             : 
      82             :       final positionMap =
      83           2 :           await _methodChannel.invokeMethod('getLastKnownPosition', parameters);
      84             : 
      85           1 :       return positionMap != null ? Position.fromMap(positionMap) : null;
      86           1 :     } on PlatformException catch (e) {
      87           1 :       _handlePlatformException(e);
      88             : 
      89             :       rethrow;
      90             :     }
      91             :   }
      92             : 
      93             :   @override
      94           1 :   Future<Position> getCurrentPosition({
      95             :     LocationAccuracy desiredAccuracy = LocationAccuracy.best,
      96             :     bool forceAndroidLocationManager = false,
      97             :     Duration? timeLimit,
      98             :   }) async {
      99           1 :     final locationOptions = LocationOptions(
     100             :       accuracy: desiredAccuracy,
     101             :       forceAndroidLocationManager: forceAndroidLocationManager,
     102             :     );
     103             : 
     104             :     try {
     105             :       Future<dynamic> positionFuture;
     106             : 
     107             :       if (timeLimit != null) {
     108             :         positionFuture = _methodChannel
     109           1 :             .invokeMethod(
     110             :               'getCurrentPosition',
     111           1 :               locationOptions.toJson(),
     112             :             )
     113           1 :             .timeout(timeLimit);
     114             :       } else {
     115           1 :         positionFuture = _methodChannel.invokeMethod(
     116             :           'getCurrentPosition',
     117           1 :           locationOptions.toJson(),
     118             :         );
     119             :       }
     120             : 
     121           1 :       final positionMap = await positionFuture;
     122           1 :       return Position.fromMap(positionMap);
     123           1 :     } on PlatformException catch (e) {
     124           1 :       _handlePlatformException(e);
     125             : 
     126             :       rethrow;
     127             :     }
     128             :   }
     129             : 
     130           1 :   @override
     131             :   Stream<ServiceStatus> getServiceStatusStream() {
     132           1 :     if (_serviceStatusStream != null) {
     133           1 :       return _serviceStatusStream!;
     134             :     }
     135             :     var serviceStatusStream =
     136           1 :         _serviceStatusEventChannel.receiveBroadcastStream();
     137             : 
     138           1 :     _serviceStatusStream = serviceStatusStream
     139           3 :         .map((dynamic element) => ServiceStatus.values[element as int])
     140           2 :         .handleError((error) {
     141           1 :       _serviceStatusStream = null;
     142           1 :       if (error is PlatformException) {
     143           1 :         _handlePlatformException(error);
     144             :       }
     145             :       throw error;
     146             :     });
     147             : 
     148           1 :     return _serviceStatusStream!;
     149             :   }
     150             : 
     151           1 :   @override
     152             :   Stream<Position> getPositionStream({
     153             :     LocationAccuracy desiredAccuracy = LocationAccuracy.best,
     154             :     int distanceFilter = 0,
     155             :     bool forceAndroidLocationManager = false,
     156             :     int timeInterval = 0,
     157             :     Duration? timeLimit,
     158             :   }) {
     159           1 :     final locationOptions = LocationOptions(
     160             :       accuracy: desiredAccuracy,
     161             :       distanceFilter: distanceFilter,
     162             :       forceAndroidLocationManager: forceAndroidLocationManager,
     163             :       timeInterval: timeInterval,
     164             :     );
     165           1 :     if (_positionStream != null) {
     166           1 :       return _positionStream!;
     167             :     }
     168           1 :     var originalStream = _eventChannel.receiveBroadcastStream(
     169           1 :       locationOptions.toJson(),
     170             :     );
     171           1 :     var positionStream = _wrapStream(originalStream);
     172             : 
     173             :     if (timeLimit != null) {
     174           1 :       positionStream = positionStream.timeout(
     175             :         timeLimit,
     176           1 :         onTimeout: (s) {
     177           2 :           s.addError(TimeoutException(
     178             :             'Time limit reached while waiting for position update.',
     179             :             timeLimit,
     180             :           ));
     181           1 :           s.close();
     182           1 :           _positionStream = null;
     183             :         },
     184             :       );
     185             :     }
     186             : 
     187           1 :     _positionStream = positionStream
     188           2 :         .map<Position>((dynamic element) =>
     189           2 :             Position.fromMap(element.cast<String, dynamic>()))
     190           1 :         .handleError(
     191           1 :       (error) {
     192           1 :         _positionStream = null;
     193           1 :         if (error is PlatformException) {
     194           1 :           _handlePlatformException(error);
     195             :         }
     196             :         throw error;
     197             :       },
     198             :     );
     199           1 :     return _positionStream!;
     200             :   }
     201             : 
     202           1 :   Stream<dynamic> _wrapStream(Stream<dynamic> incoming) {
     203             :     late StreamSubscription subscription;
     204             :     late StreamController<dynamic> controller;
     205           1 :     controller = StreamController<dynamic>(
     206           1 :       onListen: () {
     207           1 :         subscription = incoming.listen(
     208           2 :           (item) => controller.add(item),
     209           2 :           onError: (error) => controller.addError(error),
     210           2 :           onDone: () => controller.close(),
     211             :         );
     212             :       },
     213           1 :       onCancel: () {
     214           1 :         subscription.cancel();
     215           1 :         _positionStream = null;
     216             :       },
     217             :     );
     218           2 :     return controller.stream.asBroadcastStream();
     219             :   }
     220             : 
     221             :   @override
     222           1 :   Future<bool> openAppSettings() async => _methodChannel
     223           1 :       .invokeMethod<bool>('openAppSettings')
     224           2 :       .then((value) => value ?? false);
     225             : 
     226             :   @override
     227           1 :   Future<bool> openLocationSettings() async => _methodChannel
     228           1 :       .invokeMethod<bool>('openLocationSettings')
     229           2 :       .then((value) => value ?? false);
     230             : 
     231           1 :   void _handlePlatformException(PlatformException exception) {
     232           1 :     switch (exception.code) {
     233           1 :       case 'ACTIVITY_MISSING':
     234           2 :         throw ActivityMissingException(exception.message);
     235           1 :       case 'LOCATION_SERVICES_DISABLED':
     236           1 :         throw LocationServiceDisabledException();
     237           1 :       case 'LOCATION_SUBSCRIPTION_ACTIVE':
     238           1 :         throw AlreadySubscribedException();
     239           1 :       case 'PERMISSION_DEFINITIONS_NOT_FOUND':
     240           2 :         throw PermissionDefinitionsNotFoundException(exception.message);
     241           1 :       case 'PERMISSION_DENIED':
     242           2 :         throw PermissionDeniedException(exception.message);
     243           1 :       case 'PERMISSION_REQUEST_IN_PROGRESS':
     244           2 :         throw PermissionRequestInProgressException(exception.message);
     245           1 :       case 'LOCATION_UPDATE_FAILURE':
     246           2 :         throw PositionUpdateException(exception.message);
     247             :       default:
     248             :         throw exception;
     249             :     }
     250             :   }
     251             : }

Generated by: LCOV version 1.15