From 88746d5706741ff3cdad12429f3b781f76bf8123 Mon Sep 17 00:00:00 2001 From: "Martin.JM" Date: Mon, 1 Apr 2024 06:43:19 +0200 Subject: [PATCH] [Huawei] Hookup GPS values --- .../devices/huawei/HuaweiCoordinator.java | 1 + .../devices/huawei/HuaweiPacket.java | 2 + .../devices/huawei/AsynchronousResponse.java | 14 ++++ .../devices/huawei/HuaweiBRSupport.java | 7 ++ .../devices/huawei/HuaweiLESupport.java | 6 ++ .../devices/huawei/HuaweiSupportProvider.java | 59 +++++++++++++- .../requests/GetGpsParameterRequest.java | 48 ++++++++++++ .../huawei/requests/SendGpsDataRequest.java | 77 +++++++++++++++++++ 8 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/GetGpsParameterRequest.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendGpsDataRequest.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiCoordinator.java index 39d1eb3ee..381cac712 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiCoordinator.java @@ -202,6 +202,7 @@ public class HuaweiCoordinator { notifications.add(R.xml.devicesettings_donotdisturb_allday_liftwirst_notwear); // Workout + deviceSpecificSettings.addRootScreen(DeviceSpecificSettingsScreen.WORKOUT, R.xml.devicesettings_workout_send_gps_to_band); // Other deviceSpecificSettings.addRootScreen(R.xml.devicesettings_find_phone); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiPacket.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiPacket.java index 066162748..07f1b8c23 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiPacket.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/huawei/HuaweiPacket.java @@ -509,6 +509,8 @@ public class HuaweiPacket { switch (this.commandId) { case GpsAndTime.GpsParameters.id: return new GpsAndTime.GpsParameters.Response(paramsProvider).fromPacket(this); + case GpsAndTime.GpsStatus.id: + return new GpsAndTime.GpsStatus.Response(paramsProvider).fromPacket(this); case GpsAndTime.GpsData.id: return new GpsAndTime.GpsData.Response(paramsProvider).fromPacket(this); default: diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/AsynchronousResponse.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/AsynchronousResponse.java index 8ae597c65..00ccf6981 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/AsynchronousResponse.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/AsynchronousResponse.java @@ -45,9 +45,12 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Calls; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.DeviceConfig; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.FindPhone; +import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.GpsAndTime; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Menstrual; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.MusicControl; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Weather; +import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationListener; +import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationManager; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.Request; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetPhoneInfoRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendMenstrualModifyTimeRequest; @@ -98,6 +101,7 @@ public class AsynchronousResponse { handlePhoneInfo(response); handleMenstrualModifyTime(response); handleWeatherCheck(response); + handleGpsRequest(response); } catch (Request.ResponseParseException e) { LOG.error("Response parse exception", e); } @@ -395,4 +399,14 @@ public class AsynchronousResponse { // TODO: send back weather? } } + + private void handleGpsRequest(HuaweiPacket response) { + if (response.serviceId == GpsAndTime.id && response.commandId == GpsAndTime.GpsStatus.id) { + if (!(response instanceof GpsAndTime.GpsStatus.Response)) { + // TODO: exception? + return; + } + support.setGps(((GpsAndTime.GpsStatus.Response) response).enableGps); + } + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiBRSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiBRSupport.java index 999810f91..c56a8dd49 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiBRSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiBRSupport.java @@ -16,6 +16,8 @@ along with this program. If not, see . */ package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei; +import android.location.Location; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; @@ -123,4 +125,9 @@ public class HuaweiBRSupport extends AbstractBTBRDeviceSupport { public void onSendWeather(ArrayList weatherSpecs) { supportProvider.onSendWeather(weatherSpecs); } + + @Override + public void onSetGpsLocation(Location location) { + supportProvider.onSetGpsLocation(location); + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiLESupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiLESupport.java index bff89da96..d8245eb8e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiLESupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiLESupport.java @@ -18,6 +18,7 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCharacteristic; +import android.location.Location; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -131,4 +132,9 @@ public class HuaweiLESupport extends AbstractBTLEDeviceSupport { public void onSendWeather(ArrayList weatherSpecs) { supportProvider.onSendWeather(weatherSpecs); } + + @Override + public void onSetGpsLocation(Location location) { + supportProvider.onSetGpsLocation(location); + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java index b022fcc84..c13756e23 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/HuaweiSupportProvider.java @@ -19,6 +19,7 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei; import android.bluetooth.BluetoothGattCharacteristic; import android.content.Context; import android.content.SharedPreferences; +import android.location.Location; import android.widget.Toast; import androidx.annotation.NonNull; @@ -43,6 +44,7 @@ import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator; +import nodomain.freeyourgadget.gadgetbridge.devices.EventHandler; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiConstants; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiCoordinatorSupplier; @@ -50,6 +52,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiCoordinatorSupp import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiCrypto; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiSampleProvider; +import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.GpsAndTime; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Weather; import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Workout; import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst; @@ -62,6 +65,7 @@ import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutPaceSample; import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutPaceSampleDao; import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSummarySample; import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutSummarySampleDao; +import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationManager; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.entities.Alarm; import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession; @@ -77,10 +81,12 @@ import nodomain.freeyourgadget.gadgetbridge.model.RecordedDataTypes; import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.AcceptAgreementsRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetEventAlarmList; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetGpsParameterRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetNotificationConstraintsRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetSmartAlarmList; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendExtendedAccountRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendGpsAndTimeToDeviceRequest; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendGpsDataRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendWeatherCurrentRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendNotifyHeartRateCapabilityRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendNotifyRestHeartRateCapabilityRequest; @@ -107,7 +113,6 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.Alar import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.DebugRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetActivityTypeRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.Request; -import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendAccountRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.Request.RequestCallback; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetAuthRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetBatteryLevelRequest; @@ -168,6 +173,8 @@ public class HuaweiSupportProvider { private MusicStateSpec musicStateSpec = null; private MusicSpec musicSpec = null; + private GpsAndTime.GpsParameters.Response gpsParametersResponse = null; + private final HuaweiPacket.ParamsProvider paramsProvider = new HuaweiPacket.ParamsProvider(); protected ResponseManager responseManager = new ResponseManager(this); @@ -220,6 +227,39 @@ public class HuaweiSupportProvider { } } + public void setGps(boolean start) { + EventHandler handler; + if (isBLE()) + handler = leSupport; + else + handler = brSupport; + if (start) { + if (!GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress()).getBoolean(DeviceSettingsPreferenceConst.PREF_WORKOUT_SEND_GPS_TO_BAND, false)) + return; + if (gpsParametersResponse == null) { + GetGpsParameterRequest gpsParameterRequest = new GetGpsParameterRequest(this); + gpsParameterRequest.setFinalizeReq(new RequestCallback() { + @Override + public void call() { + GBLocationManager.start(getContext(), handler); + } + }); + try { + gpsParameterRequest.doPerform(); + } catch (IOException e) { + GB.toast(context, "Failed to get GPS parameters", Toast.LENGTH_SHORT, GB.ERROR, e); + LOG.error("Failed to get GPS parameters", e); + } + } else + GBLocationManager.start(getContext(), handler); + } else + GBLocationManager.stop(getContext(), handler); + } + + public void setGpsParametersResponse(GpsAndTime.GpsParameters.Response response) { + this.gpsParametersResponse = response; + } + protected nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder initializeDevice(nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder builder) { this.gbDevice = leSupport.getDevice(); this.context = leSupport.getContext(); @@ -1768,4 +1808,21 @@ public class HuaweiSupportProvider { LOG.error("Failed to send weather", e); } } + + public void onSetGpsLocation(Location location) { + if (gpsParametersResponse == null) { + GB.toast(context, "Received location without knowing supported parameters", Toast.LENGTH_SHORT, GB.ERROR); + LOG.error("Received location without knowing supported parameters"); + return; + } + + SendGpsDataRequest sendGpsDataRequest = new SendGpsDataRequest(this, location, gpsParametersResponse); + try { + sendGpsDataRequest.doPerform(); + } catch (IOException e) { + // TODO: Use translatable string + GB.toast(context, "Failed to send GPS data", Toast.LENGTH_SHORT, GB.ERROR, e); + LOG.error("Failed to send GPS data", e); + } + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/GetGpsParameterRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/GetGpsParameterRequest.java new file mode 100644 index 000000000..2f022152e --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/GetGpsParameterRequest.java @@ -0,0 +1,48 @@ +/* Copyright (C) 2024 Martin.JM + + This file is part of Gadgetbridge. + + Gadgetbridge is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Gadgetbridge is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ +package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests; + +import java.util.List; + +import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket; +import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.GpsAndTime; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider; + +public class GetGpsParameterRequest extends Request { + + public GetGpsParameterRequest(HuaweiSupportProvider support) { + super(support); + this.serviceId = GpsAndTime.id; + this.commandId = GpsAndTime.GpsParameters.id; + } + + @Override + protected List createRequest() throws RequestCreationException { + try { + return new GpsAndTime.GpsParameters.Request(this.paramsProvider).serialize(); + } catch (HuaweiPacket.CryptoException e) { + throw new RequestCreationException(e); + } + } + + @Override + protected void processResponse() throws ResponseParseException { + if (!(receivedPacket instanceof GpsAndTime.GpsParameters.Response)) + throw new ResponseTypeMismatchException(receivedPacket, GpsAndTime.GpsParameters.Response.class); + supportProvider.setGpsParametersResponse((GpsAndTime.GpsParameters.Response) receivedPacket); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendGpsDataRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendGpsDataRequest.java new file mode 100644 index 000000000..fadf5715b --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huawei/requests/SendGpsDataRequest.java @@ -0,0 +1,77 @@ +/* Copyright (C) 2024 Martin.JM + + This file is part of Gadgetbridge. + + Gadgetbridge is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Gadgetbridge is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . */ +package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests; + +import android.location.Location; + +import java.util.ArrayList; +import java.util.List; + +import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiPacket; +import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.GpsAndTime; +import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiSupportProvider; + +public class SendGpsDataRequest extends Request { + Location location; + GpsAndTime.GpsParameters.Response gpsParametersResponse; + + public SendGpsDataRequest(HuaweiSupportProvider support, Location location, GpsAndTime.GpsParameters.Response gpsParametersResponse) { + super(support); + this.serviceId = GpsAndTime.id; + this.commandId = GpsAndTime.GpsData.id; + this.location = location; + this.gpsParametersResponse = gpsParametersResponse; + } + + @Override + protected List createRequest() throws RequestCreationException { + ArrayList gpsList = new ArrayList<>(); + GpsAndTime.GpsData.Request.GpsDataContainer gpsData = new GpsAndTime.GpsData.Request.GpsDataContainer(); + + if (this.gpsParametersResponse.supportsSpeed && location.hasSpeed()) { + gpsData.hasSpeed = true; + gpsData.speed = (short) location.getSpeed(); + } + if (this.gpsParametersResponse.supportsAltitude && location.hasAltitude()) { + gpsData.hasAltitude = true; + gpsData.altitude = (short) location.getAltitude(); + } + if (this.gpsParametersResponse.supportsLatLon) { + gpsData.hasLatLon = true; + gpsData.lat = location.getLatitude(); + gpsData.lon = location.getLongitude(); + } + if (this.gpsParametersResponse.supportsDirection && location.hasBearing()) { + gpsData.hasBearing = true; + gpsData.bearing = location.getBearing(); + } + if (this.gpsParametersResponse.supportsPrecision && location.hasAccuracy()) { + gpsData.hasAccuracy = true; + gpsData.accuracy = location.getAccuracy(); + } + + gpsList.add(gpsData); + try { + return new GpsAndTime.GpsData.Request( + this.paramsProvider, + gpsList + ).serialize(); + } catch (HuaweiPacket.CryptoException e) { + throw new RequestCreationException(e); + } + } +}