location wip wip wip

This commit is contained in:
José Rebelo 2024-04-22 22:10:32 +01:00
parent 919441cfa8
commit 86fa0a0205
6 changed files with 174 additions and 38 deletions

View File

@ -30,6 +30,7 @@ public enum DeviceSpecificSettingsScreen {
DEVELOPER("pref_screen_developer", R.xml.devicesettings_root_developer),
DISPLAY("pref_screen_display", R.xml.devicesettings_root_display),
GENERIC("pref_screen_generic", R.xml.devicesettings_root_generic),
LOCATION("pref_screen_location", R.xml.devicesettings_root_location),
NOTIFICATIONS("pref_screen_notifications", R.xml.devicesettings_root_notifications),
DATE_TIME("pref_screen_date_time", R.xml.devicesettings_root_date_time),
WORKOUT("pref_screen_workout", R.xml.devicesettings_root_workout),

View File

@ -39,6 +39,9 @@ public abstract class GarminCoordinator extends AbstractBLEDeviceCoordinator {
final List<Integer> notifications = deviceSpecificSettings.addRootScreen(DeviceSpecificSettingsScreen.NOTIFICATIONS);
notifications.add(R.xml.devicesettings_send_app_notifications);
final List<Integer> location = deviceSpecificSettings.addRootScreen(DeviceSpecificSettingsScreen.LOCATION);
location.add(R.xml.devicesettings_workout_send_gps_to_band);
final List<Integer> connection = deviceSpecificSettings.addRootScreen(DeviceSpecificSettingsScreen.CONNECTION);
connection.add(R.xml.devicesettings_high_mtu);

View File

@ -2,6 +2,8 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.location.Location;
import android.os.Build;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -26,6 +28,8 @@ import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminPreferences;
import nodomain.freeyourgadget.gadgetbridge.devices.vivomovehr.GarminCapability;
import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationManager;
import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.LocationProviderType;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
@ -33,6 +37,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
import nodomain.freeyourgadget.gadgetbridge.model.Weather;
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
import nodomain.freeyourgadget.gadgetbridge.proto.vivomovehr.GdiCore;
import nodomain.freeyourgadget.gadgetbridge.proto.vivomovehr.GdiDeviceStatus;
import nodomain.freeyourgadget.gadgetbridge.proto.vivomovehr.GdiFindMyWatch;
import nodomain.freeyourgadget.gadgetbridge.proto.vivomovehr.GdiSmartProto;
@ -78,6 +83,8 @@ public class GarminSupport extends AbstractBTLEDeviceSupport implements ICommuni
private Timer musicStateTimer;
private final List<FileType> supportedFileTypeList = new ArrayList<>();
private final List<GdiCore.CoreService.Request> locationRequestsList = new ArrayList<>();
public GarminSupport() {
super(LOG);
addSupportedService(CommunicatorV1.UUID_SERVICE_GARMIN_GFDI);
@ -94,8 +101,10 @@ public class GarminSupport extends AbstractBTLEDeviceSupport implements ICommuni
@Override
public void dispose() {
super.dispose();
LOG.info("Garmin dispose()");
stopLocationUpdate();
stopMusicTimer();
super.dispose();
}
private void stopMusicTimer() {
@ -548,5 +557,69 @@ public class GarminSupport extends AbstractBTLEDeviceSupport implements ICommuni
return dir;
}
public void processLocationUpdateRequest(final boolean enable, final List<GdiCore.CoreService.Request> requestsList) {
if (enable) {
boolean useGPS = false;
for (GdiCore.CoreService.Request request: requestsList) {
if (GdiCore.CoreService.DataType.REALTIME_TRACKING.equals(request.getRequested())) {
useGPS = true;
break;
}
}
if (useGPS)
GBLocationManager.start(getContext(), this);
else
GBLocationManager.start(getContext(), this, LocationProviderType.NETWORK, 5*60*1000);
//TODO: spin up several listener according to the required precision and timeouts
this.locationRequestsList.clear();
this.locationRequestsList.addAll(requestsList);
//OpenTracksController.startRecording(deviceSupport.getContext());
} else {
stopLocationUpdate();
}
}
private void stopLocationUpdate() {
this.locationRequestsList.clear();
GBLocationManager.stop(getContext(), this);
//OpenTracksController.stopRecording(deviceSupport.getContext());
}
@Override
public void onSetGpsLocation(final Location location) {
final GdiCore.CoreService.LatLon positionForWatch = GdiCore.CoreService.LatLon.newBuilder()
.setLat((int) ((location.getLatitude() * 2.147483648E9d) / 180.0d))
.setLon((int) ((location.getLongitude() * 2.147483648E9d) / 180.0d))
.build();
float vAccuracy = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
vAccuracy = location.getVerticalAccuracyMeters();
}
GdiCore.CoreService.LocationUpdatedNotification.Builder locationUpdatedNotification = GdiCore.CoreService.LocationUpdatedNotification.newBuilder();
for (GdiCore.CoreService.Request req : this.locationRequestsList) {
locationUpdatedNotification.addLocationData(
GdiCore.CoreService.LocationData.newBuilder()
.setPosition(positionForWatch)
.setAltitude((float) location.getAltitude())
.setTimestamp(GarminTimeUtils.javaMillisToGarminTimestamp(location.getTime()))
.setHAccuracy(location.getAccuracy())
.setVAccuracy(vAccuracy)
.setPositionType(req.getRequested())
.setBearing(location.getBearing())
.setSpeed(location.getSpeed())
);
}
final ProtobufMessage locationUpdatedNotificationRequest = protocolBufferHandler.prepareProtobufRequest(
GdiSmartProto.Smart.newBuilder().setCoreService(
GdiCore.CoreService.newBuilder().
setLocationUpdatedNotification(locationUpdatedNotification)
).build()
);
sendOutgoingMessage(locationUpdatedNotificationRequest);
}
}

View File

@ -0,0 +1,34 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin;
import android.location.Location;
import android.os.Build;
import nodomain.freeyourgadget.gadgetbridge.proto.vivomovehr.GdiCore;
public final class GarminUtils {
private GarminUtils() {
// utility class
}
public static GdiCore.CoreService.LocationData toLocationData(final Location location, final GdiCore.CoreService.DataType dataType) {
final GdiCore.CoreService.LatLon positionForWatch = GdiCore.CoreService.LatLon.newBuilder()
.setLat((int) ((location.getLatitude() * 2.147483648E9d) / 180.0d))
.setLon((int) ((location.getLongitude() * 2.147483648E9d) / 180.0d))
.build();
float vAccuracy = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
vAccuracy = location.getVerticalAccuracyMeters();
}
return GdiCore.CoreService.LocationData.newBuilder()
.setPosition(positionForWatch)
.setAltitude((float) location.getAltitude())
.setTimestamp(GarminTimeUtils.javaMillisToGarminTimestamp(location.getTime()))
.setHAccuracy(location.getAccuracy())
.setVAccuracy(vAccuracy)
.setPositionType(dataType)
.setBearing(location.getBearing())
.setSpeed(location.getSpeed())
.build();
}
}

View File

@ -1,5 +1,7 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin;
import android.location.Location;
import com.google.protobuf.InvalidProtocolBufferException;
import org.apache.commons.lang3.ArrayUtils;
@ -12,6 +14,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo;
import nodomain.freeyourgadget.gadgetbridge.proto.vivomovehr.GdiCalendarService;
import nodomain.freeyourgadget.gadgetbridge.proto.vivomovehr.GdiCore;
@ -23,6 +26,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.http.HttpHand
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.GFDIMessage;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.ProtobufMessage;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.status.ProtobufStatusMessage;
import nodomain.freeyourgadget.gadgetbridge.service.devices.pebble.webview.CurrentPosition;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
import nodomain.freeyourgadget.gadgetbridge.util.calendar.CalendarEvent;
import nodomain.freeyourgadget.gadgetbridge.util.calendar.CalendarManager;
@ -69,9 +73,7 @@ public class ProtocolBufferHandler implements MessageHandler {
}
boolean processed = false;
if (smart.hasCoreService()) { //TODO: unify request and response???
processed = true;
processProtobufCoreResponse(smart.getCoreService());
// return prepareProtobufResponse(processProtobufCoreRequest(smart.getCoreService()), message.getRequestId());
return prepareProtobufResponse(processProtobufCoreRequest(smart.getCoreService()), message.getRequestId());
}
if (smart.hasCalendarService()) {
return prepareProtobufResponse(processProtobufCalendarRequest(smart.getCalendarService()), message.getRequestId());
@ -176,14 +178,6 @@ public class ProtocolBufferHandler implements MessageHandler {
).build();
}
private void processProtobufCoreResponse(GdiCore.CoreService coreService) {
if (coreService.hasSyncResponse()) {
final GdiCore.CoreService.SyncResponse syncResponse = coreService.getSyncResponse();
LOG.info("Received sync status: {}", syncResponse.getStatus());
}
LOG.warn("Unknown CoreService response: {}", coreService);
}
private void processProtobufDeviceStatusResponse(GdiDeviceStatus.DeviceStatusService deviceStatusService) {
if (deviceStatusService.hasRemoteDeviceBatteryStatusResponse()) {
final GdiDeviceStatus.DeviceStatusService.RemoteDeviceBatteryStatusResponse batteryStatusResponse = deviceStatusService.getRemoteDeviceBatteryStatusResponse();
@ -202,32 +196,54 @@ public class ProtocolBufferHandler implements MessageHandler {
LOG.warn("Unknown DeviceStatusService response: {}", deviceStatusService);
}
// private GdiSmartProto.Smart processProtobufCoreRequest(GdiCore.CoreService coreService) {
// if (coreService.hasLocationUpdatedSetEnabledRequest()) { //TODO: enable location support in devicesupport
// LOG.debug("Location CoreService: {}", coreService);
//
// final GdiCore.CoreService.LocationUpdatedSetEnabledRequest locationUpdatedSetEnabledRequest = coreService.getLocationUpdatedSetEnabledRequest();
//
// LOG.info("Received locationUpdatedSetEnabledRequest status: {}", locationUpdatedSetEnabledRequest.getEnabled());
//
// GdiCore.CoreService.LocationUpdatedSetEnabledResponse.Builder response = GdiCore.CoreService.LocationUpdatedSetEnabledResponse.newBuilder()
// .setStatus(GdiCore.CoreService.LocationUpdatedSetEnabledResponse.Status.OK);
//
// //TODO: check and follow the preference in coordinator (see R.xml.devicesettings_workout_send_gps_to_band )
// if(locationUpdatedSetEnabledRequest.getEnabled()) {
// response.addRequests(GdiCore.CoreService.LocationUpdatedSetEnabledResponse.Requested.newBuilder()
// .setRequested(locationUpdatedSetEnabledRequest.getRequests(0).getRequested())
// .setStatus(GdiCore.CoreService.LocationUpdatedSetEnabledResponse.Requested.RequestedStatus.OK));
// }
//
// deviceSupport.processLocationUpdateRequest(locationUpdatedSetEnabledRequest.getEnabled(), locationUpdatedSetEnabledRequest.getRequestsList());
//
// return GdiSmartProto.Smart.newBuilder().setCoreService(
// GdiCore.CoreService.newBuilder().setLocationUpdatedSetEnabledResponse(response)).build();
// }
// LOG.warn("Unknown CoreService request: {}", coreService);
// return null;
// }
private GdiSmartProto.Smart processProtobufCoreRequest(GdiCore.CoreService coreService) {
if (coreService.hasSyncResponse()) {
final GdiCore.CoreService.SyncResponse syncResponse = coreService.getSyncResponse();
LOG.info("Received sync status: {}", syncResponse.getStatus());
return null;
}
if (coreService.hasGetLocationRequest()) {
final Location location = new CurrentPosition().getLastKnownLocation();
final GdiCore.CoreService.GetLocationResponse.Builder response = GdiCore.CoreService.GetLocationResponse.newBuilder();
if (location.getLatitude() == 0 && location.getLongitude() == 0) {
response.setStatus(GdiCore.CoreService.GetLocationResponse.Status.NO_VALID_LOCATION);
} else {
response.setStatus(GdiCore.CoreService.GetLocationResponse.Status.OK)
.setLocationData(GarminUtils.toLocationData(location, GdiCore.CoreService.DataType.GENERAL_LOCATION));
}
return GdiSmartProto.Smart.newBuilder().setCoreService(
GdiCore.CoreService.newBuilder().setGetLocationResponse(response)).build();
}
if (coreService.hasLocationUpdatedSetEnabledRequest()) {
LOG.debug("Location CoreService: {}", coreService);
final GdiCore.CoreService.LocationUpdatedSetEnabledRequest locationUpdatedSetEnabledRequest = coreService.getLocationUpdatedSetEnabledRequest();
LOG.info("Received locationUpdatedSetEnabledRequest status: {}", locationUpdatedSetEnabledRequest.getEnabled());
GdiCore.CoreService.LocationUpdatedSetEnabledResponse.Builder response = GdiCore.CoreService.LocationUpdatedSetEnabledResponse.newBuilder();
final boolean sendGpsPref = deviceSupport.getDevicePrefs().getBoolean(DeviceSettingsPreferenceConst.PREF_WORKOUT_SEND_GPS_TO_BAND, false);
if (locationUpdatedSetEnabledRequest.getEnabled() && sendGpsPref) {
response.setStatus(GdiCore.CoreService.LocationUpdatedSetEnabledResponse.Status.OK)
.addRequests(GdiCore.CoreService.LocationUpdatedSetEnabledResponse.Requested.newBuilder()
.setRequested(locationUpdatedSetEnabledRequest.getRequests(0).getRequested())
.setStatus(GdiCore.CoreService.LocationUpdatedSetEnabledResponse.Requested.RequestedStatus.OK));
} else {
response.setStatus(GdiCore.CoreService.LocationUpdatedSetEnabledResponse.Status.UNAVAILABLE);
}
deviceSupport.processLocationUpdateRequest(locationUpdatedSetEnabledRequest.getEnabled(), locationUpdatedSetEnabledRequest.getRequestsList());
return GdiSmartProto.Smart.newBuilder().setCoreService(
GdiCore.CoreService.newBuilder().setLocationUpdatedSetEnabledResponse(response)).build();
}
LOG.warn("Unknown CoreService request: {}", coreService);
return null;
}
private void processProtobufFindMyWatchResponse(GdiFindMyWatch.FindMyWatchService findMyWatchService) {
if (findMyWatchService.hasCancelRequest()) {

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceScreen
android:icon="@drawable/ic_gps_location"
android:key="pref_screen_location"
android:persistent="false"
android:title="@string/pref_header_location">
</PreferenceScreen>
</androidx.preference.PreferenceScreen>