1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-07-03 11:33:19 +02:00

Garmin: Configure contacts

This commit is contained in:
José Rebelo 2024-05-19 16:27:13 +01:00 committed by Daniele Gobbetti
parent f3cc07af27
commit ca8d595493
6 changed files with 175 additions and 1 deletions

View File

@ -50,7 +50,6 @@ import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
import nodomain.freeyourgadget.gadgetbridge.entities.User;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
public class ConfigureContacts extends AbstractGBActivity {

View File

@ -107,6 +107,9 @@ public abstract class GarminCoordinator extends AbstractBLEDeviceCoordinator {
notifications.add(R.xml.devicesettings_canned_reply_16);
notifications.add(R.xml.devicesettings_canned_dismisscall_16);
}
if (getContactsSlotCount(device) > 0) {
notifications.add(R.xml.devicesettings_contacts);
}
final List<Integer> location = deviceSpecificSettings.addRootScreen(DeviceSpecificSettingsScreen.LOCATION);
location.add(R.xml.devicesettings_workout_send_gps_to_band);
@ -197,6 +200,15 @@ public abstract class GarminCoordinator extends AbstractBLEDeviceCoordinator {
return 0;
}
@Override
public int getContactsSlotCount(final GBDevice device) {
if (getPrefs(device).getBoolean(GarminPreferences.PREF_FEAT_CONTACTS, false)) {
return 50;
}
return 0;
}
protected static Prefs getPrefs(final GBDevice device) {
return new Prefs(GBApplication.getDeviceSpecificSharedPrefs(device.getAddress()));
}

View File

@ -5,6 +5,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.CheckSums;
public class GarminPreferences {
public static final String PREF_GARMIN_CAPABILITIES = "garmin_capabilities";
public static final String PREF_FEAT_CANNED_MESSAGES = "feat_canned_messages";
public static final String PREF_FEAT_CONTACTS = "feat_contacts";
public static final String PREF_AGPS_KNOWN_URLS = "garmin_agps_known_urls";
public static final String PREF_GARMIN_AGPS_STATUS = "garmin_agps_status_%s";
public static final String PREF_GARMIN_AGPS_UPDATE_TIME = "garmin_agps_update_time_%s";

View File

@ -0,0 +1,111 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.http;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Locale;
import java.util.Random;
import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminPreferences;
import nodomain.freeyourgadget.gadgetbridge.entities.Contact;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GarminContacts;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.GarminSupport;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
public class ContactsHandler {
private static final Logger LOG = LoggerFactory.getLogger(ContactsHandler.class);
private final GarminSupport deviceSupport;
public ContactsHandler(final GarminSupport deviceSupport) {
this.deviceSupport = deviceSupport;
}
public GarminHttpResponse handleRequest(final GarminHttpRequest request) {
if (!request.getPath().equals("/device-gateway/usercontact/contacts")) {
LOG.warn("Unknown contacts path {}", request.getPath());
return null;
}
if (!"application/octet-stream".equals(request.getHeaders().get("accept"))) {
// We only support protobuf replies
LOG.warn("Requested contacts content type '{}' not supported", request.getHeaders().get("accept"));
return null;
}
// Mark contacts as supported
final Prefs devicePrefs = deviceSupport.getDevicePrefs();
devicePrefs.getPreferences().edit()
.putBoolean(GarminPreferences.PREF_FEAT_CONTACTS, true)
.apply();
final GarminContacts.Response.Builder responseContacts = GarminContacts.Response.newBuilder();
final List<Contact> contacts = DBHelper.getContacts(deviceSupport.getDevice());
for (final Contact contact : contacts) {
final GarminContacts.Contact.Builder responseContact = GarminContacts.Contact.newBuilder()
.setId(randomHex(32).toUpperCase(Locale.ROOT))
.setFullName(contact.getName())
.setFirstName(contact.getName())
.setLastName("")
.addPhone(
GarminContacts.Phone.newBuilder()
.setNumber(contact.getNumber())
.setUnk2(1)
.setUnk3(1)
.setUnk4(0)
.setUnk5(new Random().nextInt(65535) + 65535)
.setUnk6(0)
.setUnk7(0)
.setUnk8("")
.setUnk9(1)
.setId(UUID.randomUUID().toString())
.setUnk11(1)
.addUnk12(GarminContacts.Unk12.newBuilder().setUnk1(1).setUnk2(5))
.addUnk12(GarminContacts.Unk12.newBuilder().setUnk1(2).setUnk2(5))
)
.setUnk8(0)
.setUnk9(0)
.setUpdateTime(System.currentTimeMillis())
.setUnk12(0)
.setUnk21(0);
responseContacts.addContact(responseContact);
}
final ActivityUser activityUser = new ActivityUser();
final GarminContacts.Contact.Builder self = GarminContacts.Contact.newBuilder()
.setId("SELF")
.setFullName(activityUser.getName())
.setFirstName(activityUser.getName())
.setLastName("")
.setUnk7("")
.setUnk8(0)
.setUnk9(0)
.setUnk10(0)
.setUnk12(0)
.setUnk21(0)
.setUpdateTime(System.currentTimeMillis());
responseContacts.setSelf(self);
final GarminHttpResponse response = new GarminHttpResponse();
response.setStatus(200);
response.getHeaders().put("Content-Type", "application/octet-stream");
response.setBody(responseContacts.build().toByteArray());
return response;
}
public static String randomHex(final int numChars) {
final Random r = new Random();
final StringBuilder sb = new StringBuilder();
while (sb.length() < numChars) {
sb.append(Integer.toHexString(r.nextInt()));
}
return sb.toString().substring(0, numChars);
}
}

View File

@ -19,9 +19,11 @@ public class HttpHandler {
private static final Logger LOG = LoggerFactory.getLogger(HttpHandler.class);
private final AgpsHandler agpsHandler;
private final ContactsHandler contactsHandler;
public HttpHandler(GarminSupport deviceSupport) {
agpsHandler = new AgpsHandler(deviceSupport);
contactsHandler = new ContactsHandler(deviceSupport);
}
public GdiHttpService.HttpService handle(final GdiHttpService.HttpService httpService) {
@ -52,6 +54,9 @@ public class HttpHandler {
} else if (request.getPath().startsWith("/ephemeris/")) {
LOG.info("Got AGPS request for {}", request.getPath());
response = agpsHandler.handleAgpsRequest(request);
} else if (request.getPath().startsWith("/device-gateway/usercontact/")) {
LOG.info("Got contacts request for {}", request.getPath());
response = contactsHandler.handleRequest(request);
} else {
LOG.warn("Unhandled path {}", request.getPath());
response = null;

View File

@ -0,0 +1,46 @@
syntax = "proto2";
package garmin;
option java_package = "nodomain.freeyourgadget.gadgetbridge.proto.garmin";
option java_outer_classname = "GarminContacts";
message Response {
repeated Contact contact = 1;
optional Contact self = 2;
}
message Contact {
optional string id = 1; // "SELF" on self
optional string fullName = 2;
optional string firstName = 3;
optional string lastName = 4;
repeated Phone phone = 5;
optional string unk7 = 7; // ""
optional uint32 unk8 = 8; // 0
optional uint32 unk9 = 9; // 0
optional uint32 unk10 = 10; // 0
optional uint64 updateTime = 11;
optional uint32 unk12 = 12; // 0
optional uint32 unk21 = 21; // 0
}
message Phone {
optional string number = 1;
optional uint32 unk2 = 2; // 1
optional uint32 unk3 = 3; // 1
optional uint32 unk4 = 4; // 0
optional uint32 unk5 = 5; // random number
optional uint32 unk6 = 6; // 0
optional uint32 unk7 = 7; // 0
optional string unk8 = 8; // ""
optional uint32 unk9 = 9; // 1
optional string id = 10; // uuid
optional uint32 unk11 = 11; // 1
repeated Unk12 unk12 = 12; // 1/5, 2/5
}
message Unk12 {
optional uint32 unk1 = 1; // 1/2
optional uint32 unk2 = 2; // 5
}