diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 6b6c8dc..3216e39 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -5,8 +5,13 @@ android:required="false" /> - + + + + + @@ -53,6 +58,17 @@ + + + + + diff --git a/lib/main.dart b/lib/main.dart index 44c1baa..e5bc4d8 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,7 @@ import 'dart:convert'; import 'dart:async'; +import 'dart:isolate'; +import 'dart:ui'; import 'dart:math' as math; import 'package:flutter/foundation.dart'; import 'package:flutter/rendering.dart'; @@ -23,8 +25,11 @@ import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:in_app_purchase/in_app_purchase.dart'; import 'plugins/dynamic_multi_column_layout.dart'; import 'plugins/spoiler_card.dart'; -import 'package:workmanager/workmanager.dart' as workManager; -import 'package:geolocator/geolocator.dart'; +//import 'package:workmanager/workmanager.dart' as workManager; +//import 'package:geolocator/geolocator.dart'; +import 'package:background_locator/background_locator.dart'; +import 'package:background_locator/location_dto.dart'; +import 'package:background_locator/location_settings.dart'; import 'package:battery/battery.dart'; import 'package:firebase_crashlytics/firebase_crashlytics.dart'; import 'package:flutter_webview_plugin/flutter_webview_plugin.dart' as standaloneWebview; @@ -213,9 +218,12 @@ class _HAClientAppState extends State { StreamSubscription> _purchaseUpdateSubscription; StreamSubscription _themeChangeSubscription; AppTheme _currentTheme = AppTheme.defaultTheme; + + ReceivePort port = ReceivePort(); @override void initState() { + InAppPurchaseConnection.enablePendingPurchases(); final Stream purchaseUpdates = InAppPurchaseConnection.instance.purchaseUpdatedStream; @@ -228,11 +236,18 @@ class _HAClientAppState extends State { _currentTheme = event.theme; }); }); + /* workManager.Workmanager.initialize( updateDeviceLocationIsolate, isInDebugMode: false ); + */ super.initState(); + IsolateNameServer.registerPortWithName(port.sendPort, LocationManager.isolateName); + port.listen((dynamic data) { + // do something with data + }); + initPlatformState(); } void _handlePurchaseUpdates(purchase) { @@ -253,6 +268,10 @@ class _HAClientAppState extends State { } } + Future initPlatformState() async { + await BackgroundLocator.initialize(); + } + // This widget is the root of your application. @override Widget build(BuildContext context) { diff --git a/lib/managers/location_manager.class.dart b/lib/managers/location_manager.class.dart index e0563d0..b692634 100644 --- a/lib/managers/location_manager.class.dart +++ b/lib/managers/location_manager.class.dart @@ -26,7 +26,7 @@ class LocationManager { defaultUpdateIntervalMinutes); _isRunning = prefs.getBool("location-enabled") ?? false; if (_isRunning) { - await _startLocationService(); + //await _startLocationService(); } } @@ -57,6 +57,20 @@ class LocationManager { } _startLocationService() async { + Logger.d('Starting location tracking'); + BackgroundLocator.registerLocationUpdate( + locationCallback, + //optional + androidNotificationCallback: locationNotificationCallback, + settings: LocationSettings( + notificationTitle: "HA Client location tracking", + notificationMsg: "HA Client is updating your device location", + wakeLockTime: 20, + autoStop: false, + interval: 10 + ), + ); + /* String webhookId = ConnectionManager().webhookId; String httpWebHost = ConnectionManager().httpWebHost; if (webhookId != null && webhookId.isNotEmpty) { @@ -100,14 +114,81 @@ class LocationManager { ); } } + */ } _stopLocationService() async { - Logger.d("Canceling previous schedule if any..."); - await workManager.Workmanager.cancelAll(); + Logger.d('Stopping location tracking'); + IsolateNameServer.removePortNameMapping(isolateName); + BackgroundLocator.unRegisterLocationUpdate(); + /*Logger.d("Canceling previous schedule if any..."); + await workManager.Workmanager.cancelAll();*/ + } + + static const String isolateName = "HAClientLocatorIsolate"; + + static void locationCallback(LocationDto locationDto) async { + print('[Background location] Got location: $locationDto'); + sendLocationData(locationDto); + final SendPort send = IsolateNameServer.lookupPortByName(isolateName); + send?.send(locationDto); + } + + static Future sendLocationData(LocationDto location) async { + print('[Background location] Loading settings...'); + SharedPreferences prefs = await SharedPreferences.getInstance(); + String domain = prefs.getString('hassio-domain'); + String port = prefs.getString('hassio-port'); + String webhookId = prefs.getString('app-webhook-id'); + String httpWebHost = + "${prefs.getString('hassio-res-protocol')}://$domain:$port"; + if (webhookId != null && webhookId.isNotEmpty) { + String url = "$httpWebHost/api/webhook/$webhookId"; + Map headers = {}; + headers["Content-Type"] = "application/json"; + Map data = { + "type": "update_location", + "data": { + "gps": [], + "gps_accuracy": 0, + "battery": 100 + } + }; + try { + if (location.longitude != null && location.latitude != null) { + data["data"]["gps"] = [location.latitude, location.longitude]; + data["data"]["gps_accuracy"] = location.accuracy; + print('[Background location] Sending...'); + try { + http.Response response = await http.post( + url, + headers: headers, + body: json.encode(data) + ); + if (response.statusCode >= 200 && response.statusCode < 300) { + print('[Background location] Success!'); + } else { + print('[Background location] Error sending data: ${response.statusCode}'); + } + } catch(e) { + print('[Background location] Error sending data: $e'); + } + } else { + print('[Background location] Error. Location is null'); + } + } catch (e) { + print('[Background location] Error: $e'); + } + } + } + + + static void locationNotificationCallback() { + print('[Background location] User clicked on the notification'); } updateDeviceLocation() async { + /* try { Logger.d("[Foreground location] Started"); Geolocator geolocator = Geolocator(); @@ -150,10 +231,12 @@ class LocationManager { } catch (e, stack) { Logger.e('Foreground location error: ${e.toSTring()}', stacktrace: stack); } + */ } } +/* void updateDeviceLocationIsolate() { workManager.Workmanager.executeTask((backgroundTask, data) async { //print("[Background $backgroundTask] Started"); @@ -241,4 +324,5 @@ void updateDeviceLocationIsolate() { print("[Background $backgroundTask] Finished.");*/ return true; }); -} \ No newline at end of file +} +*/ \ No newline at end of file diff --git a/lib/pages/settings/integration_settings.part.dart b/lib/pages/settings/integration_settings.part.dart index bb1d1f2..03c7924 100644 --- a/lib/pages/settings/integration_settings.part.dart +++ b/lib/pages/settings/integration_settings.part.dart @@ -53,9 +53,11 @@ class _IntegrationSettingsPageState extends State { } _switchLocationTrackingState(bool state) async { + /* if (state) { await LocationManager().updateDeviceLocation(); } + */ await LocationManager().setSettings(_locationTrackingEnabled, _locationInterval); setState(() { _wait = false; diff --git a/pubspec.yaml b/pubspec.yaml index 62cdd7e..cc6ca88 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -27,8 +27,9 @@ dependencies: flutter_secure_storage: ^3.3.3 device_info: ^0.4.1+4 flutter_local_notifications: ^1.1.6 - geolocator: ^5.3.1 - workmanager: ^0.2.2 + #geolocator: ^5.3.1 + background_locator: ^1.1.3+1 + #workmanager: ^0.2.2 battery: ^1.0.0 firebase_crashlytics: ^0.1.3+3 syncfusion_flutter_core: ^18.1.48