Resolves #49 Location tracking

This commit is contained in:
Yegor Vialov 2019-10-20 17:54:29 +00:00
parent 079070071e
commit d1ec4f36cc
10 changed files with 276 additions and 3 deletions

17
android/.project Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>android</name>
<comment>Project android created by Buildship.</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
</projectDescription>

6
android/app/.classpath Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/"/>
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
<classpathentry kind="output" path="bin/default"/>
</classpath>

23
android/app/.project Normal file
View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>app</name>
<comment>Project app created by Buildship.</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
</projectDescription>

View File

@ -4,11 +4,13 @@ import io.flutter.app.FlutterApplication;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback;
import io.flutter.plugins.GeneratedPluginRegistrant;
import be.tramckrijte.workmanager.WorkmanagerPlugin;
public class Application extends FlutterApplication implements PluginRegistrantCallback {
@Override
public void onCreate() {
super.onCreate();
WorkmanagerPlugin.setPluginRegistrantCallback(this);
}
@Override

View File

@ -27,6 +27,8 @@ import 'package:share/share.dart';
import 'plugins/dynamic_multi_column_layout.dart';
import 'plugins/spoiler_card.dart';
import 'package:uni_links/uni_links.dart';
import 'package:workmanager/workmanager.dart' as workManager;
import 'package:geolocator/geolocator.dart';
import 'utils/logger.dart';

View File

@ -163,8 +163,6 @@ class ConnectionManager {
}
}
Future _disconnect() {
Completer completer = Completer();
if (!isConnected) {

View File

@ -2,4 +2,157 @@ part of '../main.dart';
class LocationManager {
static final LocationManager _instance = LocationManager
._internal();
factory LocationManager() {
return _instance;
}
LocationManager._internal() {
init();
}
final int defaultUpdateIntervalMinutes = 15;
final String alarmId = "ha_location_background";
Duration _updateInterval;
bool _isEnabled;
void init() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.reload();
_updateInterval = Duration(minutes: prefs.getInt("location-interval") ??
defaultUpdateIntervalMinutes);
_isEnabled = prefs.getBool("location-enabled") ?? false;
if (_isEnabled) {
_startLocationService();
}
}
void setSettings(bool enabled, int interval) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
if (interval != _updateInterval.inMinutes) {
prefs.setInt("location-interval", interval);
_updateInterval = Duration(minutes: interval);
}
if (enabled && !_isEnabled) {
Logger.d("Enabling location service");
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool("location-enabled", enabled);
_isEnabled = true;
_startLocationService();
updateDeviceLocation();
} else if (!enabled && _isEnabled) {
Logger.d("Disabling location service");
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool("location-enabled", enabled);
_isEnabled = false;
_stopLocationService();
}
}
void _startLocationService() async {
Logger.d("Scheduling location update for every ${_updateInterval
.inMinutes} minutes...");
await workManager.Workmanager.registerPeriodicTask(
alarmId,
"simplePeriodicTask",
frequency: _updateInterval,
existingWorkPolicy: workManager.ExistingWorkPolicy.replace,
constraints: workManager.Constraints(
networkType: workManager.NetworkType.connected
)
);
}
void _stopLocationService() async {
Logger.d("Canceling previous schedule if any...");
await workManager.Workmanager.cancelByUniqueName(alarmId);
}
void updateDeviceLocation() async {
if (_isEnabled) {
if (ConnectionManager().webhookId != null &&
ConnectionManager().webhookId.isNotEmpty) {
String url = "${ConnectionManager()
.httpWebHost}/api/webhook/${ConnectionManager().webhookId}";
Map<String, String> headers = {};
Logger.d("[Location] Getting device location...");
Position location = await Geolocator().getCurrentPosition(
desiredAccuracy: LocationAccuracy.medium);
Logger.d("[Location] Got location: ${location.latitude} ${location
.longitude}. Sending home...");
int battery = DateTime
.now()
.hour;
var data = {
"type": "update_location",
"data": {
"gps": [location.latitude, location.longitude],
"gps_accuracy": location.accuracy,
"battery": battery
}
};
headers["Content-Type"] = "application/json";
await http.post(
url,
headers: headers,
body: json.encode(data)
);
Logger.d("[Location] ...done.");
} else {
Logger.d("[Location] No webhook id. Aborting");
}
} else {
Logger.d("[Location] Location tracking is disabled");
}
}
}
void updateDeviceLocationIsolate() {
workManager.Workmanager.executeTask((backgroundTask, _) {
print("[Location isolate] Started: $backgroundTask");
//Completer completer = Completer();
SharedPreferences.getInstance().then((prefs){
print("[Location isolate] loading settings");
String webhookId = prefs.getString('app-webhook-id');
String domain = prefs.getString('hassio-domain');
String port = prefs.getString('hassio-port');
String httpWebHost =
"${prefs.getString('hassio-res-protocol')}://$domain:$port";
if (webhookId != null && webhookId.isNotEmpty) {
Logger.d("[Location isolate] Getting device location...");
Geolocator().getCurrentPosition(desiredAccuracy: LocationAccuracy.medium).then((location) {
Logger.d("[Location isolate] Got location: ${location.latitude} ${location.longitude}. Sending home...");
int battery = DateTime.now().hour;
String url = "$httpWebHost/api/webhook/$webhookId";
Map<String, String> headers = {};
headers["Content-Type"] = "application/json";
var data = {
"type": "update_location",
"data": {
"gps": [location.latitude, location.longitude],
"gps_accuracy": location.accuracy,
"battery": battery
}
};
http.post(
url,
headers: headers,
body: json.encode(data)
).catchError((e) {
print("[Location isolate] Error sending data: ${e.toString()}");
}).then((_) {
print("[Location isolate] done!");
});
});
} else {
print("[Location isolate] No webhook id. Aborting");
}
});
return Future.value(true);
});
}

View File

@ -109,6 +109,7 @@ class _MainPageState extends ReceiveShareState<MainPage> with WidgetsBindingObse
_subscribe().then((_) {
ConnectionManager().init(loadSettings: true, forceReconnect: true).then((__){
_fetchData();
LocationManager();
StartupUserMessagesManager().checkMessagesToShow();
}, onError: (e) {
_setErrorState(e);

View File

@ -9,9 +9,40 @@ class ConfigPanelWidget extends StatefulWidget {
class _ConfigPanelWidgetState extends State<ConfigPanelWidget> {
int _locationInterval = LocationManager().defaultUpdateIntervalMinutes;
bool _locationTrackingEnabled = false;
@override
void initState() {
super.initState();
_loadSettings();
}
_loadSettings() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.reload();
SharedPreferences.getInstance().then((prefs) {
setState(() {
_locationTrackingEnabled = prefs.getBool("location-enabled") ?? false;
_locationInterval = prefs.getInt("location-interval") ?? LocationManager().defaultUpdateIntervalMinutes;
});
});
}
void incLocationInterval() {
if (_locationInterval < 720) {
setState(() {
_locationInterval = _locationInterval + 1;
});
}
}
void decLocationInterval() {
if (_locationInterval > 1) {
setState(() {
_locationInterval = _locationInterval - 1;
});
}
}
restart() {
@ -92,17 +123,55 @@ class _ConfigPanelWidgetState extends State<ConfigPanelWidget> {
)
],
),
Divider(),
Text("Location tracking", style: TextStyle(fontSize: Sizes.largeFontSize-2)),
Container(height: Sizes.rowPadding,),
Row(
children: <Widget>[
Text("Enable device location tracking"),
Switch(
value: _locationTrackingEnabled,
onChanged: (value) {
SharedPreferences.getInstance().then((prefs) => prefs.setBool("location-enabled", value));
setState(() {
_locationTrackingEnabled = value;
});
},
),
],
),
Container(height: Sizes.rowPadding,),
Text("Location update interval in minutes:"),
Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
//Expanded(child: Container(),),
FlatButton(
padding: EdgeInsets.all(0.0),
child: Text("+", style: TextStyle(fontSize: Sizes.largeFontSize)),
onPressed: () => incLocationInterval(),
),
Text("$_locationInterval", style: TextStyle(fontSize: Sizes.largeFontSize)),
FlatButton(
padding: EdgeInsets.all(0.0),
child: Text("-", style: TextStyle(fontSize: Sizes.largeFontSize)),
onPressed: () => decLocationInterval(),
),
],
)
],
),
),
),
LinkToWebConfig(name: "Home AssistantConfiguration", url: ConnectionManager().httpWebHost+"/config"),
LinkToWebConfig(name: "Home Assistant configuration", url: ConnectionManager().httpWebHost+"/config"),
],
);
}
@override
void dispose() {
LocationManager().setSettings(_locationTrackingEnabled, _locationInterval);
super.dispose();
}
}

View File

@ -25,6 +25,8 @@ dependencies:
flutter_secure_storage: ^3.3.1+1
device_info: ^0.4.0+3
flutter_local_notifications: ^0.8.4
geolocator: ^5.1.4+2
workmanager: ^0.1.3
share:
git:
url: https://github.com/d-silveira/flutter-share.git