1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-11-28 21:06:50 +01:00

Zepp OS: Query supported services and encryption flag

This commit is contained in:
José Rebelo 2024-01-15 21:27:01 +00:00
parent baaee8f589
commit 3a2b02df2a
25 changed files with 118 additions and 183 deletions

View File

@ -43,6 +43,8 @@ import android.net.Uri;
import android.os.Handler;
import android.widget.Toast;
import androidx.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -57,10 +59,12 @@ import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@ -170,6 +174,7 @@ public abstract class Huami2021Support extends HuamiSupport implements ZeppOsFil
private final ZeppOsLoyaltyCardService loyaltyCardService = new ZeppOsLoyaltyCardService(this);
private final ZeppOsMusicService musicService = new ZeppOsMusicService(this);
private final Set<Short> mSupportedServices = new HashSet<>();
private final Map<Short, AbstractZeppOsService> mServiceMap = new LinkedHashMap<Short, AbstractZeppOsService>() {{
put(servicesService.getEndpoint(), servicesService);
put(fileTransferService.getEndpoint(), fileTransferService);
@ -967,33 +972,69 @@ public abstract class Huami2021Support extends HuamiSupport implements ZeppOsFil
@Override
public void phase3Initialize(final TransactionBuilder builder) {
LOG.info("2021 phase3Initialize...");
// Make sure that performInitialized is not called accidentally in here
// (eg. by creating a new TransactionBuilder).
// In those cases, the device will be initialized twice, which will change the shared
// session key during these phase3 requests and decrypting messages will fail
// session key during these requests and decrypting messages will fail
final Huami2021Coordinator coordinator = getCoordinator();
// In here, we only request the list of supported services - they will all be initialized in
// initializeServices below
mSupportedServices.clear();
servicesService.requestServices(builder);
}
LOG.info("2021 phase3Initialize...");
setUserInfo(builder);
public void addSupportedService(final short endpoint) {
mSupportedServices.add(endpoint);
}
for (final HuamiVibrationPatternNotificationType type : coordinator.getVibrationPatternNotificationTypes(gbDevice)) {
// FIXME: Can we read these from the band?
final String typeKey = type.name().toLowerCase(Locale.ROOT);
setVibrationPattern(builder, HuamiConst.PREF_HUAMI_VIBRATION_PROFILE_PREFIX + typeKey);
public void initializeServices() {
LOG.info("2021 initializeServices...");
try {
final TransactionBuilder builder = createTransactionBuilder("initialize services");
// At this point we got the service list from phase 3, so we know which
// services are supported, and whether they are encrypted or not
final Huami2021Coordinator coordinator = getCoordinator();
// TODO move this to a service
setUserInfo(builder);
// TODO move this to a service
for (final HuamiVibrationPatternNotificationType type : coordinator.getVibrationPatternNotificationTypes(gbDevice)) {
// FIXME: Can we read these from the band?
final String typeKey = type.name().toLowerCase(Locale.ROOT);
setVibrationPattern(builder, HuamiConst.PREF_HUAMI_VIBRATION_PROFILE_PREFIX + typeKey);
}
// TODO move these to a service
cannedMessagesService.requestCannedMessages(builder);
alarmsService.requestAlarms(builder);
for (AbstractZeppOsService service : mServiceMap.values()) {
if (mSupportedServices.contains(service.getEndpoint())) {
// Only initialize supported services
service.initialize(builder);
}
}
if (coordinator.supportsBluetoothPhoneCalls(gbDevice)) {
phoneService.requestCapabilities(builder);
phoneService.requestEnabled(builder);
}
builder.queue(getQueue());
} catch (Exception e) {
LOG.error("failed initializing device", e);
}
}
cannedMessagesService.requestCannedMessages(builder);
alarmsService.requestAlarms(builder);
for (AbstractZeppOsService service : mServiceMap.values()) {
service.initialize(builder);
}
if (coordinator.supportsBluetoothPhoneCalls(gbDevice)) {
phoneService.requestCapabilities(builder);
phoneService.requestEnabled(builder);
}
@Nullable
public AbstractZeppOsService getService(final short endpoint) {
return mServiceMap.get(endpoint);
}
@Override
@ -1099,6 +1140,7 @@ public abstract class Huami2021Support extends HuamiSupport implements ZeppOsFil
return;
}
// TODO: Move these services to dedicated classes, so they get the encryption correctly
switch (type) {
case CHUNKED2021_ENDPOINT_AUTH:
LOG.warn("Unexpected auth payload {}", GB.hexdump(payload));

View File

@ -18,25 +18,44 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos;
import android.content.Context;
import androidx.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.huami.Huami2021Coordinator;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.Huami2021Support;
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services.ZeppOsAlexaService;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
public abstract class AbstractZeppOsService {
private final Huami2021Support mSupport;
private static final Logger LOG = LoggerFactory.getLogger(ZeppOsAlexaService.class);
public AbstractZeppOsService(final Huami2021Support support) {
private final Huami2021Support mSupport;
private boolean encrypted;
public AbstractZeppOsService(final Huami2021Support support, final boolean encryptedDefault) {
this.mSupport = support;
this.encrypted = encryptedDefault;
}
public abstract short getEndpoint();
public abstract boolean isEncrypted();
public final boolean isEncrypted() {
return this.encrypted;
}
public final void setEncrypted(final boolean encrypted) {
if (encrypted != this.encrypted) {
LOG.warn("Replacing encrypted flag for {}, {} -> {}", this.getClass().getSimpleName(), this.encrypted, encrypted);
}
this.encrypted = encrypted;
}
public abstract void handlePayload(final byte[] payload);
@ -52,6 +71,8 @@ public abstract class AbstractZeppOsService {
public void initialize(final TransactionBuilder builder) {
// Do nothing by default
// TODO implement a "quick initialize" that runs for the same firmware + Gb versions, since
// we will already know the capabilities
}
protected Huami2021Support getSupport() {
@ -91,6 +112,7 @@ public abstract class AbstractZeppOsService {
return getSupport().getContext();
}
@Nullable
protected static Boolean booleanFromByte(final byte b) {
switch (b) {
case 0x00:

View File

@ -42,7 +42,7 @@ public class ZeppOsAgpsService extends AbstractZeppOsService {
private Callback mCallback = null;
public ZeppOsAgpsService(final Huami2021Support support) {
super(support);
super(support, false);
}
@Override
@ -50,11 +50,6 @@ public class ZeppOsAgpsService extends AbstractZeppOsService {
return ENDPOINT;
}
@Override
public boolean isEncrypted() {
return false;
}
@Override
public void handlePayload(final byte[] payload) {
switch (payload[0]) {

View File

@ -66,7 +66,7 @@ public class ZeppOsAlarmsService extends AbstractZeppOsService {
public static final int FLAG_ENABLED = 0x04;
public ZeppOsAlarmsService(final Huami2021Support support) {
super(support);
super(support, false);
}
@Override
@ -74,11 +74,6 @@ public class ZeppOsAlarmsService extends AbstractZeppOsService {
return ENDPOINT;
}
@Override
public boolean isEncrypted() {
return false;
}
@Override
public void handlePayload(final byte[] payload) {
switch (payload[0]) {

View File

@ -83,7 +83,7 @@ public class ZeppOsAlexaService extends AbstractZeppOsService {
final ByteArrayOutputStream voiceBuffer = new ByteArrayOutputStream();
public ZeppOsAlexaService(final Huami2021Support support) {
super(support);
super(support, true);
}
@Override
@ -91,11 +91,6 @@ public class ZeppOsAlexaService extends AbstractZeppOsService {
return ENDPOINT;
}
@Override
public boolean isEncrypted() {
return true;
}
@Override
public void handlePayload(final byte[] payload) {
switch (payload[0]) {

View File

@ -55,7 +55,7 @@ public class ZeppOsAppsService extends AbstractZeppOsService {
private final List<GBDeviceApp> apps = new ArrayList<>();
public ZeppOsAppsService(final Huami2021Support support) {
super(support);
super(support, false);
}
@Override
@ -63,11 +63,6 @@ public class ZeppOsAppsService extends AbstractZeppOsService {
return ENDPOINT;
}
@Override
public boolean isEncrypted() {
return false;
}
@Override
public void handlePayload(final byte[] payload) {
switch (payload[0]) {

View File

@ -50,7 +50,7 @@ public class ZeppOsCalendarService extends AbstractZeppOsService {
private int version = -1;
public ZeppOsCalendarService(final Huami2021Support support) {
super(support);
super(support, false);
}
@Override
@ -58,11 +58,6 @@ public class ZeppOsCalendarService extends AbstractZeppOsService {
return ENDPOINT;
}
@Override
public boolean isEncrypted() {
return false;
}
@Override
public void initialize(final TransactionBuilder builder) {
requestCapabilities(builder);

View File

@ -59,7 +59,7 @@ public class ZeppOsCannedMessagesService extends AbstractZeppOsService {
public static final byte CMD_REPLY_SMS_ALLOW = 0x0e;
public ZeppOsCannedMessagesService(final Huami2021Support support) {
super(support);
super(support, false);
}
@Override
@ -67,11 +67,6 @@ public class ZeppOsCannedMessagesService extends AbstractZeppOsService {
return ENDPOINT;
}
@Override
public boolean isEncrypted() {
return false;
}
@Override
public void handlePayload(final byte[] payload) {
switch (payload[0]) {

View File

@ -97,7 +97,7 @@ public class ZeppOsConfigService extends AbstractZeppOsService {
private final Map<ConfigGroup, Byte> mGroupVersions = new HashMap<>();
public ZeppOsConfigService(final Huami2021Support support) {
super(support);
super(support, true);
}
@Override
@ -105,11 +105,6 @@ public class ZeppOsConfigService extends AbstractZeppOsService {
return ENDPOINT;
}
@Override
public boolean isEncrypted() {
return true;
}
@Override
public void handlePayload(final byte[] payload) {
switch (payload[0]) {

View File

@ -47,7 +47,7 @@ public class ZeppOsContactsService extends AbstractZeppOsService {
public static final String PREF_CONTACTS_SLOT_COUNT = "zepp_os_contacts_slot_count";
public ZeppOsContactsService(final Huami2021Support support) {
super(support);
super(support, true);
}
@Override
@ -55,11 +55,6 @@ public class ZeppOsContactsService extends AbstractZeppOsService {
return ENDPOINT;
}
@Override
public boolean isEncrypted() {
return true;
}
@Override
public void handlePayload(final byte[] payload) {
switch (payload[0]) {

View File

@ -65,7 +65,7 @@ public class ZeppOsDisplayItemsService extends AbstractZeppOsService {
public static final byte DISPLAY_ITEMS_SECTION_DISABLED = 0x03;
public ZeppOsDisplayItemsService(final Huami2021Support support) {
super(support);
super(support, true);
}
@Override
@ -73,11 +73,6 @@ public class ZeppOsDisplayItemsService extends AbstractZeppOsService {
return ENDPOINT;
}
@Override
public boolean isEncrypted() {
return true;
}
@Override
public void handlePayload(final byte[] payload) {
switch (payload[0]) {

View File

@ -56,7 +56,7 @@ public class ZeppOsFileTransferService extends AbstractZeppOsService {
private int mChunkSize = -1;
public ZeppOsFileTransferService(final Huami2021Support support) {
super(support);
super(support, false);
}
@Override
@ -64,11 +64,6 @@ public class ZeppOsFileTransferService extends AbstractZeppOsService {
return ENDPOINT;
}
@Override
public boolean isEncrypted() {
return false;
}
@Override
public void handlePayload(final byte[] payload) {
byte session;

View File

@ -47,7 +47,7 @@ public class ZeppOsFtpServerService extends AbstractZeppOsService {
private Callback mCallback = null;
public ZeppOsFtpServerService(final Huami2021Support support) {
super(support);
super(support, true);
}
@Override
@ -55,11 +55,6 @@ public class ZeppOsFtpServerService extends AbstractZeppOsService {
return ENDPOINT;
}
@Override
public boolean isEncrypted() {
return true;
}
@Override
public void handlePayload(final byte[] payload) {
switch (payload[0]) {

View File

@ -45,7 +45,7 @@ public class ZeppOsHttpService extends AbstractZeppOsService {
public static final byte RESPONSE_NO_INTERNET = 0x02;
public ZeppOsHttpService(final Huami2021Support support) {
super(support);
super(support, true);
}
@Override
@ -53,11 +53,6 @@ public class ZeppOsHttpService extends AbstractZeppOsService {
return ENDPOINT;
}
@Override
public boolean isEncrypted() {
return true;
}
@Override
public void handlePayload(final byte[] payload) {
switch (payload[0]) {

View File

@ -63,7 +63,7 @@ public class ZeppOsLogsService extends AbstractZeppOsService {
private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
public ZeppOsLogsService(final Huami2021Support support) {
super(support);
super(support, false);
}
@Override
@ -71,11 +71,6 @@ public class ZeppOsLogsService extends AbstractZeppOsService {
return ENDPOINT;
}
@Override
public boolean isEncrypted() {
return false;
}
@Override
public void handlePayload(final byte[] payload) {
switch (payload[0]) {

View File

@ -58,7 +58,7 @@ public class ZeppOsLoyaltyCardService extends AbstractZeppOsService {
public static final String PREF_VERSION = "zepp_os_loyalty_cards_version";
public ZeppOsLoyaltyCardService(final Huami2021Support support) {
super(support);
super(support, false);
}
@Override
@ -66,11 +66,6 @@ public class ZeppOsLoyaltyCardService extends AbstractZeppOsService {
return ENDPOINT;
}
@Override
public boolean isEncrypted() {
return false;
}
@Override
public void handlePayload(final byte[] payload) {
switch (payload[0]) {

View File

@ -66,7 +66,7 @@ public class ZeppOsMorningUpdatesService extends AbstractZeppOsService {
}};
public ZeppOsMorningUpdatesService(Huami2021Support support) {
super(support);
super(support, false);
}
@Override
@ -74,11 +74,6 @@ public class ZeppOsMorningUpdatesService extends AbstractZeppOsService {
return ENDPOINT;
}
@Override
public boolean isEncrypted() {
return false;
}
@Override
public void handlePayload(byte[] payload) {
switch (payload[0]) {

View File

@ -45,7 +45,7 @@ public class ZeppOsMusicService extends AbstractZeppOsService {
private static final byte BUTTON_VOLUME_DOWN = 0x06;
public ZeppOsMusicService(final Huami2021Support support) {
super(support);
super(support, false);
}
@Override
@ -53,11 +53,6 @@ public class ZeppOsMusicService extends AbstractZeppOsService {
return ENDPOINT;
}
@Override
public boolean isEncrypted() {
return false;
}
@Override
public void handlePayload(final byte[] payload) {
switch (payload[0]) {

View File

@ -75,7 +75,7 @@ public class ZeppOsNotificationService extends AbstractZeppOsService {
private final ZeppOsFileTransferService fileTransferService;
public ZeppOsNotificationService(final Huami2021Support support, final ZeppOsFileTransferService fileTransferService) {
super(support);
super(support, true);
this.fileTransferService = fileTransferService;
}
@ -84,11 +84,6 @@ public class ZeppOsNotificationService extends AbstractZeppOsService {
return ENDPOINT;
}
@Override
public boolean isEncrypted() {
return true;
}
@Override
public void handlePayload(final byte[] payload) {
final GBDeviceEventNotificationControl deviceEvtNotificationControl = new GBDeviceEventNotificationControl();

View File

@ -55,7 +55,7 @@ public class ZeppOsPhoneService extends AbstractZeppOsService {
private int version = 0;
public ZeppOsPhoneService(final Huami2021Support support) {
super(support);
super(support, true);
}
@Override
@ -63,11 +63,6 @@ public class ZeppOsPhoneService extends AbstractZeppOsService {
return ENDPOINT;
}
@Override
public boolean isEncrypted() {
return true;
}
@Override
public void handlePayload(final byte[] payload) {
switch (payload[0]) {

View File

@ -61,7 +61,7 @@ public class ZeppOsRemindersService extends AbstractZeppOsService {
private static final String PREF_CAPABILITY = "huami_2021_capability_reminders";
public ZeppOsRemindersService(final Huami2021Support support) {
super(support);
super(support, false);
}
@Override
@ -69,11 +69,6 @@ public class ZeppOsRemindersService extends AbstractZeppOsService {
return ENDPOINT;
}
@Override
public boolean isEncrypted() {
return false;
}
@Override
public void handlePayload(final byte[] payload) {
switch (payload[0]) {

View File

@ -16,30 +16,15 @@
along with this program. If not, see <https://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.services;
import android.annotation.SuppressLint;
import android.widget.Toast;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePreferences;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.Huami2021Support;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.zeppos.AbstractZeppOsService;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
public class ZeppOsServicesService extends AbstractZeppOsService {
private static final Logger LOG = LoggerFactory.getLogger(ZeppOsServicesService.class);
@ -50,7 +35,7 @@ public class ZeppOsServicesService extends AbstractZeppOsService {
public static final byte CMD_RET_LIST = 0x04;
public ZeppOsServicesService(final Huami2021Support support) {
super(support);
super(support, false);
}
@Override
@ -58,11 +43,6 @@ public class ZeppOsServicesService extends AbstractZeppOsService {
return ENDPOINT;
}
@Override
public boolean isEncrypted() {
return false;
}
@Override
public void handlePayload(final byte[] payload) {
switch (payload[0]) {
@ -74,11 +54,6 @@ public class ZeppOsServicesService extends AbstractZeppOsService {
}
}
@Override
public void initialize(final TransactionBuilder builder) {
//requestServices(builder);
}
public void requestServices(final TransactionBuilder builder) {
write(builder, CMD_GET_LIST);
}
@ -95,11 +70,17 @@ public class ZeppOsServicesService extends AbstractZeppOsService {
final byte encryptedByte = buf.get();
final Boolean encrypted = booleanFromByte(encryptedByte);
LOG.debug("Service: endpoint={} encrypted={}", String.format("%04x", endpoint), encrypted);
final AbstractZeppOsService service = getSupport().getService(endpoint);
// TODO use this to initialize the services supported by the device
LOG.debug("Service: endpoint={} encrypted={} known={}", String.format("%04x", endpoint), encrypted, service != null);
if (service != null && encrypted != null) {
service.setEncrypted(encrypted);
}
}
getSupport().initializeServices();
final int remainingBytes = buf.limit() - buf.position();
if (remainingBytes != 0) {
LOG.warn("There are {} bytes remaining in the buffer", remainingBytes);

View File

@ -124,7 +124,7 @@ public class ZeppOsShortcutCardsService extends AbstractZeppOsService {
private int maxCards = 0;
public ZeppOsShortcutCardsService(final Huami2021Support support) {
super(support);
super(support, true);
}
@Override
@ -132,11 +132,6 @@ public class ZeppOsShortcutCardsService extends AbstractZeppOsService {
return ENDPOINT;
}
@Override
public boolean isEncrypted() {
return true;
}
@Override
public void handlePayload(final byte[] payload) {
switch (payload[0]) {

View File

@ -112,7 +112,7 @@ public class ZeppOsWatchfaceService extends AbstractZeppOsService {
final List<GBDeviceApp> watchfaces = new ArrayList<>();
public ZeppOsWatchfaceService(final Huami2021Support support) {
super(support);
super(support, true);
}
@Override
@ -120,11 +120,6 @@ public class ZeppOsWatchfaceService extends AbstractZeppOsService {
return ENDPOINT;
}
@Override
public boolean isEncrypted() {
return true;
}
@Override
public void handlePayload(final byte[] payload) {
switch (payload[0]) {

View File

@ -47,7 +47,7 @@ public class ZeppOsWifiService extends AbstractZeppOsService {
private Callback mCallback = null;
public ZeppOsWifiService(final Huami2021Support support) {
super(support);
super(support, true);
}
@Override
@ -55,11 +55,6 @@ public class ZeppOsWifiService extends AbstractZeppOsService {
return ENDPOINT;
}
@Override
public boolean isEncrypted() {
return true;
}
@Override
public void handlePayload(final byte[] payload) {
switch (payload[0]) {