mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-04 17:27:24 +01:00
Garmin: Configure contacts
This commit is contained in:
parent
f3cc07af27
commit
ca8d595493
@ -50,7 +50,6 @@ import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.User;
|
import nodomain.freeyourgadget.gadgetbridge.entities.User;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
|
||||||
|
|
||||||
|
|
||||||
public class ConfigureContacts extends AbstractGBActivity {
|
public class ConfigureContacts extends AbstractGBActivity {
|
||||||
|
@ -107,6 +107,9 @@ public abstract class GarminCoordinator extends AbstractBLEDeviceCoordinator {
|
|||||||
notifications.add(R.xml.devicesettings_canned_reply_16);
|
notifications.add(R.xml.devicesettings_canned_reply_16);
|
||||||
notifications.add(R.xml.devicesettings_canned_dismisscall_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);
|
final List<Integer> location = deviceSpecificSettings.addRootScreen(DeviceSpecificSettingsScreen.LOCATION);
|
||||||
location.add(R.xml.devicesettings_workout_send_gps_to_band);
|
location.add(R.xml.devicesettings_workout_send_gps_to_band);
|
||||||
@ -197,6 +200,15 @@ public abstract class GarminCoordinator extends AbstractBLEDeviceCoordinator {
|
|||||||
return 0;
|
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) {
|
protected static Prefs getPrefs(final GBDevice device) {
|
||||||
return new Prefs(GBApplication.getDeviceSpecificSharedPrefs(device.getAddress()));
|
return new Prefs(GBApplication.getDeviceSpecificSharedPrefs(device.getAddress()));
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.CheckSums;
|
|||||||
public class GarminPreferences {
|
public class GarminPreferences {
|
||||||
public static final String PREF_GARMIN_CAPABILITIES = "garmin_capabilities";
|
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_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_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_STATUS = "garmin_agps_status_%s";
|
||||||
public static final String PREF_GARMIN_AGPS_UPDATE_TIME = "garmin_agps_update_time_%s";
|
public static final String PREF_GARMIN_AGPS_UPDATE_TIME = "garmin_agps_update_time_%s";
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -19,9 +19,11 @@ public class HttpHandler {
|
|||||||
private static final Logger LOG = LoggerFactory.getLogger(HttpHandler.class);
|
private static final Logger LOG = LoggerFactory.getLogger(HttpHandler.class);
|
||||||
|
|
||||||
private final AgpsHandler agpsHandler;
|
private final AgpsHandler agpsHandler;
|
||||||
|
private final ContactsHandler contactsHandler;
|
||||||
|
|
||||||
public HttpHandler(GarminSupport deviceSupport) {
|
public HttpHandler(GarminSupport deviceSupport) {
|
||||||
agpsHandler = new AgpsHandler(deviceSupport);
|
agpsHandler = new AgpsHandler(deviceSupport);
|
||||||
|
contactsHandler = new ContactsHandler(deviceSupport);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GdiHttpService.HttpService handle(final GdiHttpService.HttpService httpService) {
|
public GdiHttpService.HttpService handle(final GdiHttpService.HttpService httpService) {
|
||||||
@ -52,6 +54,9 @@ public class HttpHandler {
|
|||||||
} else if (request.getPath().startsWith("/ephemeris/")) {
|
} else if (request.getPath().startsWith("/ephemeris/")) {
|
||||||
LOG.info("Got AGPS request for {}", request.getPath());
|
LOG.info("Got AGPS request for {}", request.getPath());
|
||||||
response = agpsHandler.handleAgpsRequest(request);
|
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 {
|
} else {
|
||||||
LOG.warn("Unhandled path {}", request.getPath());
|
LOG.warn("Unhandled path {}", request.getPath());
|
||||||
response = null;
|
response = null;
|
||||||
|
46
app/src/main/proto/garmin/garmin_contacts.proto
Normal file
46
app/src/main/proto/garmin/garmin_contacts.proto
Normal 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
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user