mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2025-01-10 09:01:55 +01:00
First piece of Garmin Vivomove HR support basics
- `DeviceType` definition - Definition of activity sample table - Coordinator and sample provider
This commit is contained in:
parent
bdb904faf9
commit
114f6fcbf0
@ -90,8 +90,9 @@ public class GBDaoGenerator {
|
||||
addCasioGBX100Sample(schema, user, device);
|
||||
addFitProActivitySample(schema, user, device);
|
||||
addPineTimeActivitySample(schema, user, device);
|
||||
|
||||
addHybridHRActivitySample(schema, user, device);
|
||||
addVivomoveHrActivitySample(schema, user, device);
|
||||
|
||||
addCalendarSyncState(schema, device);
|
||||
addAlarms(schema, user, device);
|
||||
addReminders(schema, user, device);
|
||||
@ -461,6 +462,19 @@ public class GBDaoGenerator {
|
||||
return activitySample;
|
||||
}
|
||||
|
||||
private static Entity addVivomoveHrActivitySample(Schema schema, Entity user, Entity device) {
|
||||
final Entity activitySample = addEntity(schema, "VivomoveHrActivitySample");
|
||||
activitySample.implementsSerializable();
|
||||
addCommonActivitySampleProperties("AbstractActivitySample", activitySample, user, device);
|
||||
activitySample.addIntProperty(SAMPLE_STEPS).notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||
activitySample.addIntProperty(SAMPLE_RAW_KIND).notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||
activitySample.addIntProperty(SAMPLE_RAW_INTENSITY).notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||
activitySample.addIntProperty(SAMPLE_HEART_RATE).notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||
activitySample.addIntProperty("caloriesBurnt");
|
||||
activitySample.addIntProperty("floorsClimbed");
|
||||
return activitySample;
|
||||
}
|
||||
|
||||
private static Entity addWatchXPlusHealthActivitySample(Schema schema, Entity user, Entity device) {
|
||||
Entity activitySample = addEntity(schema, "WatchXPlusActivitySample");
|
||||
activitySample.implementsSerializable();
|
||||
|
@ -66,7 +66,8 @@ vendor's servers.
|
||||
- [Galaxy Buds Pro](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Galaxy-Buds#galaxy-buds-pro)
|
||||
- [Galaxy Buds2](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Galaxy-Buds#galaxy-buds2)
|
||||
- [Galaxy Buds2 Pro](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Galaxy-Buds#galaxy-buds2-pro)
|
||||
|
||||
- Garmin
|
||||
- Vívomove HR
|
||||
- [HPlus Devices (e.g. ZeBand)](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/HPlus)
|
||||
- ID115
|
||||
- [iTag](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/iTag)
|
||||
|
@ -0,0 +1,142 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.vivomovehr;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public enum GarminCapability {
|
||||
CONNECT_MOBILE_FIT_LINK,
|
||||
GOLF_FIT_LINK,
|
||||
VIVOKID_JR_FIT_LINK,
|
||||
SYNC,
|
||||
DEVICE_INITIATES_SYNC,
|
||||
HOST_INITIATED_SYNC_REQUESTS,
|
||||
GNCS,
|
||||
ADVANCED_MUSIC_CONTROLS,
|
||||
FIND_MY_PHONE,
|
||||
FIND_MY_WATCH,
|
||||
CONNECTIQ_HTTP,
|
||||
CONNECTIQ_SETTINGS,
|
||||
CONNECTIQ_WATCH_APP_DOWNLOAD,
|
||||
CONNECTIQ_WIDGET_DOWNLOAD,
|
||||
CONNECTIQ_WATCH_FACE_DOWNLOAD,
|
||||
CONNECTIQ_DATA_FIELD_DOWNLOAD,
|
||||
CONNECTIQ_APP_MANAGEMENT,
|
||||
COURSE_DOWNLOAD,
|
||||
WORKOUT_DOWNLOAD,
|
||||
GOLF_COURSE_DOWNLOAD,
|
||||
DELTA_SOFTWARE_UPDATE_FILES,
|
||||
FITPAY,
|
||||
LIVETRACK,
|
||||
LIVETRACK_AUTO_START,
|
||||
LIVETRACK_MESSAGING,
|
||||
GROUP_LIVETRACK,
|
||||
WEATHER_CONDITIONS,
|
||||
WEATHER_ALERTS,
|
||||
GPS_EPHEMERIS_DOWNLOAD,
|
||||
EXPLICIT_ARCHIVE,
|
||||
SWING_SENSOR,
|
||||
SWING_SENSOR_REMOTE,
|
||||
INCIDENT_DETECTION,
|
||||
TRUEUP,
|
||||
INSTANT_INPUT,
|
||||
SEGMENTS,
|
||||
AUDIO_PROMPT_LAP,
|
||||
AUDIO_PROMPT_PACE_SPEED,
|
||||
AUDIO_PROMPT_HEART_RATE,
|
||||
AUDIO_PROMPT_POWER,
|
||||
AUDIO_PROMPT_NAVIGATION,
|
||||
AUDIO_PROMPT_CADENCE,
|
||||
SPORT_GENERIC,
|
||||
SPORT_RUNNING,
|
||||
SPORT_CYCLING,
|
||||
SPORT_TRANSITION,
|
||||
SPORT_FITNESS_EQUIPMENT,
|
||||
SPORT_SWIMMING,
|
||||
STOP_SYNC_AFTER_SOFTWARE_UPDATE,
|
||||
CALENDAR,
|
||||
WIFI_SETUP,
|
||||
SMS_NOTIFICATIONS,
|
||||
BASIC_MUSIC_CONTROLS,
|
||||
AUDIO_PROMPTS_SPEECH,
|
||||
DELTA_SOFTWARE_UPDATES,
|
||||
GARMIN_DEVICE_INFO_FILE_TYPE,
|
||||
SPORT_PROFILE_SETUP,
|
||||
HSA_SUPPORT,
|
||||
SPORT_STRENGTH,
|
||||
SPORT_CARDIO,
|
||||
UNION_PAY,
|
||||
IPASS,
|
||||
CIQ_AUDIO_CONTENT_PROVIDER,
|
||||
UNION_PAY_INTERNATIONAL,
|
||||
REQUEST_PAIR_FLOW,
|
||||
LOCATION_UPDATE,
|
||||
LTE_SUPPORT,
|
||||
DEVICE_DRIVEN_LIVETRACK_SUPPORT,
|
||||
CUSTOM_CANNED_TEXT_LIST_SUPPORT,
|
||||
EXPLORE_SYNC,
|
||||
INCIDENT_DETECT_AND_ASSISTANCE,
|
||||
CURRENT_TIME_REQUEST_SUPPORT,
|
||||
CONTACTS_SUPPORT,
|
||||
LAUNCH_REMOTE_CIQ_APP_SUPPORT,
|
||||
DEVICE_MESSAGES,
|
||||
WAYPOINT_TRANSFER,
|
||||
MULTI_LINK_SERVICE,
|
||||
OAUTH_CREDENTIALS,
|
||||
GOLF_9_PLUS_9,
|
||||
ANTI_THEFT_ALARM,
|
||||
INREACH,
|
||||
EVENT_SHARING;
|
||||
|
||||
public static final Set<GarminCapability> ALL_CAPABILITIES = new HashSet<>(values().length);
|
||||
private static final Map<Integer, GarminCapability> FROM_ORDINAL = new HashMap<>(values().length);
|
||||
|
||||
static {
|
||||
for (GarminCapability cap : values()) {
|
||||
FROM_ORDINAL.put(cap.ordinal(), cap);
|
||||
ALL_CAPABILITIES.add(cap);
|
||||
}
|
||||
}
|
||||
|
||||
public static Set<GarminCapability> setFromBinary(byte[] bytes) {
|
||||
final Set<GarminCapability> result = new HashSet<>(GarminCapability.values().length);
|
||||
int current = 0;
|
||||
for (int b : bytes) {
|
||||
for (int curr = 1; curr < 0x100; curr <<= 1) {
|
||||
if ((b & curr) != 0) {
|
||||
result.add(FROM_ORDINAL.get(current));
|
||||
}
|
||||
++current;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static byte[] setToBinary(Set<GarminCapability> capabilities) {
|
||||
final GarminCapability[] values = values();
|
||||
final byte[] result = new byte[(values.length + 7) / 8];
|
||||
int bytePos = 0;
|
||||
int bitPos = 0;
|
||||
for (int i = 0; i < values.length; ++i) {
|
||||
if (capabilities.contains(FROM_ORDINAL.get(i))) {
|
||||
result[bytePos] |= (1 << bitPos);
|
||||
}
|
||||
++bitPos;
|
||||
if (bitPos >= 8) {
|
||||
bitPos = 0;
|
||||
++bytePos;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String setToString(Set<GarminCapability> capabilities) {
|
||||
final StringBuilder result = new StringBuilder();
|
||||
for (GarminCapability cap : capabilities) {
|
||||
if (result.length() > 0) result.append(", ");
|
||||
result.append(cap.name());
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.vivomovehr;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public class VivomoveConstants {
|
||||
public static final UUID UUID_SERVICE_GARMIN_1 = UUID.fromString("6A4E2401-667B-11E3-949A-0800200C9A66");
|
||||
public static final UUID UUID_SERVICE_GARMIN_2 = UUID.fromString("6A4E2500-667B-11E3-949A-0800200C9A66");
|
||||
|
||||
public static final UUID UUID_CHARACTERISTIC_GARMIN_GFDI_SEND = UUID.fromString("6a4e4c80-667b-11e3-949a-0800200c9a66");
|
||||
public static final UUID UUID_CHARACTERISTIC_GARMIN_GFDI_RECEIVE = UUID.fromString("6a4ecd28-667b-11e3-949a-0800200c9a66");
|
||||
|
||||
public static final UUID UUID_CHARACTERISTIC_GARMIN_HEART_RATE = UUID.fromString("6a4e2501-667b-11e3-949a-0800200c9a66");
|
||||
public static final UUID UUID_CHARACTERISTIC_GARMIN_STEPS = UUID.fromString("6a4e2502-667b-11e3-949a-0800200c9a66");
|
||||
public static final UUID UUID_CHARACTERISTIC_GARMIN_CALORIES = UUID.fromString("6a4e2503-667b-11e3-949a-0800200c9a66");
|
||||
public static final UUID UUID_CHARACTERISTIC_GARMIN_STAIRS = UUID.fromString("6a4e2504-667b-11e3-949a-0800200c9a66");
|
||||
public static final UUID UUID_CHARACTERISTIC_GARMIN_INTENSITY = UUID.fromString("6a4e2505-667b-11e3-949a-0800200c9a66");
|
||||
public static final UUID UUID_CHARACTERISTIC_GARMIN_HEART_RATE_VARIATION = UUID.fromString("6a4e2507-667b-11e3-949a-0800200c9a66");
|
||||
// public static final UUID UUID_CHARACTERISTIC_GARMIN_STRESS = UUID.fromString("6a4e2508-667b-11e3-949a-0800200c9a66");
|
||||
public static final UUID UUID_CHARACTERISTIC_GARMIN_2_9 = UUID.fromString("6a4e2509-667b-11e3-949a-0800200c9a66");
|
||||
// public static final UUID UUID_CHARACTERISTIC_GARMIN_SPO2 = UUID.fromString("6a4e250c-667b-11e3-949a-0800200c9a66");
|
||||
// public static final UUID UUID_CHARACTERISTIC_GARMIN_RESPIRATION = UUID.fromString("6a4e250e-667b-11e3-949a-0800200c9a66");
|
||||
|
||||
// public static final UUID UUID_CLIENT_CHARACTERISTIC_CONFIGURATION = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
|
||||
|
||||
public static final int STATUS_ACK = 0;
|
||||
public static final int STATUS_NAK = 1;
|
||||
public static final int STATUS_UNSUPPORTED = 2;
|
||||
public static final int STATUS_DECODE_ERROR = 3;
|
||||
public static final int STATUS_CRC_ERROR = 4;
|
||||
public static final int STATUS_LENGTH_ERROR = 5;
|
||||
|
||||
public static final int GADGETBRIDGE_UNIT_NUMBER = 22222;
|
||||
|
||||
public static final int GARMIN_DEVICE_XML_FILE_INDEX = 65533;
|
||||
|
||||
// TODO: Better capability management/configuration
|
||||
// public static final Set<GarminCapability> OUR_CAPABILITIES = new HashSet<>(Arrays.asList(GarminCapability.SYNC, GarminCapability.GNCS, GarminCapability.ADVANCED_MUSIC_CONTROLS, GarminCapability.FIND_MY_PHONE, GarminCapability.WEATHER_CONDITIONS, GarminCapability.WEATHER_ALERTS, GarminCapability.DEVICE_MESSAGES, GarminCapability.SMS_NOTIFICATIONS, GarminCapability.SYNC, GarminCapability.DEVICE_INITIATES_SYNC, GarminCapability.HOST_INITIATED_SYNC_REQUESTS, GarminCapability.CALENDAR, GarminCapability.CURRENT_TIME_REQUEST_SUPPORT));
|
||||
public static final Set<GarminCapability> OUR_CAPABILITIES = GarminCapability.ALL_CAPABILITIES;
|
||||
|
||||
public static final int MAX_WRITE_SIZE = 20;
|
||||
|
||||
/**
|
||||
* Garmin zero time in seconds since Epoch: 1989-12-31T00:00:00Z
|
||||
*/
|
||||
public static final int GARMIN_TIME_EPOCH = 631065600;
|
||||
|
||||
public static final SimpleDateFormat ANCS_DATE_FORMAT = new SimpleDateFormat("yyyyMMdd'T'HHmmss", Locale.ROOT);
|
||||
|
||||
public static final int MESSAGE_RESPONSE = 5000;
|
||||
public static final int MESSAGE_REQUEST = 5001;
|
||||
public static final int MESSAGE_DOWNLOAD_REQUEST = 5002;
|
||||
public static final int MESSAGE_UPLOAD_REQUEST = 5003;
|
||||
public static final int MESSAGE_FILE_TRANSFER_DATA = 5004;
|
||||
public static final int MESSAGE_CREATE_FILE_REQUEST = 5005;
|
||||
public static final int MESSAGE_DIRECTORY_FILE_FILTER_REQUEST = 5007;
|
||||
public static final int MESSAGE_FILE_READY = 5009;
|
||||
public static final int MESSAGE_FIT_DEFINITION = 5011;
|
||||
public static final int MESSAGE_FIT_DATA = 5012;
|
||||
public static final int MESSAGE_WEATHER_REQUEST = 5014;
|
||||
public static final int MESSAGE_BATTERY_STATUS = 5023;
|
||||
public static final int MESSAGE_DEVICE_INFORMATION = 5024;
|
||||
public static final int MESSAGE_DEVICE_SETTINGS = 5026;
|
||||
public static final int MESSAGE_SYSTEM_EVENT = 5030;
|
||||
public static final int MESSAGE_SUPPORTED_FILE_TYPES_REQUEST = 5031;
|
||||
public static final int MESSAGE_NOTIFICATION_SOURCE = 5033;
|
||||
public static final int MESSAGE_GNCS_CONTROL_POINT_REQUEST = 5034;
|
||||
public static final int MESSAGE_GNCS_DATA_SOURCE = 5035;
|
||||
public static final int MESSAGE_NOTIFICATION_SERVICE_SUBSCRIPTION = 5036;
|
||||
public static final int MESSAGE_SYNC_REQUEST = 5037;
|
||||
public static final int MESSAGE_FIND_MY_PHONE = 5039;
|
||||
public static final int MESSAGE_CANCEL_FIND_MY_PHONE = 5040;
|
||||
public static final int MESSAGE_MUSIC_CONTROL_CAPABILITIES = 5042;
|
||||
public static final int MESSAGE_PROTOBUF_REQUEST = 5043;
|
||||
public static final int MESSAGE_PROTOBUF_RESPONSE = 5044;
|
||||
public static final int MESSAGE_MUSIC_CONTROL_ENTITY_UPDATE = 5049;
|
||||
public static final int MESSAGE_CONFIGURATION = 5050;
|
||||
public static final int MESSAGE_CURRENT_TIME_REQUEST = 5052;
|
||||
public static final int MESSAGE_AUTH_NEGOTIATION = 5101;
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.vivomovehr;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBException;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractDeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
|
||||
|
||||
public class VivomoveHrCoordinator extends AbstractDeviceCoordinator {
|
||||
@NonNull
|
||||
@Override
|
||||
public DeviceType getSupportedType(GBDeviceCandidate candidate) {
|
||||
if ("vívomove HR".equals(candidate.getName())) return DeviceType.VIVOMOVE_HR;
|
||||
|
||||
final boolean hasServiceUuids = candidate.getServiceUuids().length > 0;
|
||||
return hasServiceUuids && candidate.supportsService(VivomoveConstants.UUID_SERVICE_GARMIN_2) ? DeviceType.VIVOMOVE_HR : DeviceType.UNKNOWN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeviceType getDeviceType() {
|
||||
return DeviceType.VIVOMOVE_HR;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Class<? extends Activity> getPairingActivity() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsActivityDataFetching() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsActivityTracking() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SampleProvider<? extends ActivitySample> getSampleProvider(GBDevice device, DaoSession session) {
|
||||
return new VivomoveHrSampleProvider(device, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InstallHandler findInstallHandler(Uri uri, Context context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsScreenshots() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlarmSlotCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsSmartWakeup(GBDevice device) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsHeartRateMeasurement(GBDevice device) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getManufacturer() {
|
||||
return "Garmin";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsAppsManagement(GBDevice device) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Activity> getAppsManagementActivity() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsCalendarEvents() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsRealtimeData() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsWeather() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFindDevice() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device device, @NonNull DaoSession session) throws GBException {
|
||||
// nothing to delete, yet
|
||||
}
|
||||
}
|
@ -0,0 +1,229 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.vivomovehr;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import de.greenrobot.dao.AbstractDao;
|
||||
import de.greenrobot.dao.Property;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.VivomoveHrActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.VivomoveHrActivitySampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
|
||||
|
||||
public class VivomoveHrSampleProvider extends AbstractSampleProvider<VivomoveHrActivitySample> {
|
||||
public static final int RAW_TYPE_KIND_MASK = 0x0F000000;
|
||||
public static final int RAW_TYPE_KIND_ACTIVITY = 0x00000000;
|
||||
public static final int RAW_TYPE_KIND_SLEEP = 0x01000000;
|
||||
// public static final int RAW_TYPE_KIND_NOT_WORN = 0x0F000000;
|
||||
public static final int RAW_NOT_WORN = 0x0F000000;
|
||||
|
||||
public VivomoveHrSampleProvider(GBDevice device, DaoSession session) {
|
||||
super(device, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int normalizeType(int rawType) {
|
||||
if (rawType == RAW_NOT_WORN) {
|
||||
return ActivityKind.TYPE_NOT_WORN;
|
||||
}
|
||||
|
||||
switch (rawType & RAW_TYPE_KIND_MASK) {
|
||||
case RAW_TYPE_KIND_ACTIVITY:
|
||||
return normalizeActivityType(rawType & ~RAW_TYPE_KIND_MASK);
|
||||
case RAW_TYPE_KIND_SLEEP:
|
||||
return normalizeSleepType(rawType & ~RAW_TYPE_KIND_MASK);
|
||||
default:
|
||||
// ???
|
||||
return ActivityKind.TYPE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
private static int normalizeActivityType(int rawType) {
|
||||
switch (rawType) {
|
||||
case 0:
|
||||
// generic
|
||||
return ActivityKind.TYPE_ACTIVITY;
|
||||
case 1:
|
||||
// running
|
||||
return ActivityKind.TYPE_RUNNING;
|
||||
case 2:
|
||||
// cycling
|
||||
return ActivityKind.TYPE_CYCLING;
|
||||
case 3:
|
||||
// transition
|
||||
return ActivityKind.TYPE_ACTIVITY | ActivityKind.TYPE_RUNNING | ActivityKind.TYPE_WALKING | ActivityKind.TYPE_EXERCISE | ActivityKind.TYPE_SWIMMING;
|
||||
case 4:
|
||||
// fitness_equipment
|
||||
return ActivityKind.TYPE_EXERCISE;
|
||||
case 5:
|
||||
// swimming
|
||||
return ActivityKind.TYPE_SWIMMING;
|
||||
case 6:
|
||||
// walking
|
||||
return ActivityKind.TYPE_WALKING;
|
||||
case 8:
|
||||
// sedentary
|
||||
// TODO?
|
||||
return ActivityKind.TYPE_ACTIVITY;
|
||||
|
||||
default:
|
||||
return ActivityKind.TYPE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
private static int normalizeSleepType(int rawType) {
|
||||
switch (rawType) {
|
||||
case 0:
|
||||
// deep_sleep
|
||||
return ActivityKind.TYPE_DEEP_SLEEP;
|
||||
case 1:
|
||||
// light_sleep
|
||||
return ActivityKind.TYPE_LIGHT_SLEEP;
|
||||
case 2:
|
||||
// awake
|
||||
case 3:
|
||||
// more_awake
|
||||
return ActivityKind.TYPE_ACTIVITY;
|
||||
default:
|
||||
// ?
|
||||
return ActivityKind.TYPE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int toRawActivityKind(int activityKind) {
|
||||
switch (activityKind) {
|
||||
case ActivityKind.TYPE_NOT_WORN:
|
||||
return RAW_NOT_WORN;
|
||||
|
||||
case ActivityKind.TYPE_ACTIVITY:
|
||||
// generic
|
||||
//noinspection PointlessBitwiseExpression
|
||||
return RAW_TYPE_KIND_ACTIVITY | 0;
|
||||
case ActivityKind.TYPE_RUNNING:
|
||||
// running
|
||||
return RAW_TYPE_KIND_ACTIVITY | 1;
|
||||
case ActivityKind.TYPE_CYCLING:
|
||||
// cycling
|
||||
return RAW_TYPE_KIND_ACTIVITY | 2;
|
||||
case ActivityKind.TYPE_ACTIVITY | ActivityKind.TYPE_RUNNING | ActivityKind.TYPE_WALKING | ActivityKind.TYPE_EXERCISE | ActivityKind.TYPE_SWIMMING:
|
||||
return RAW_TYPE_KIND_ACTIVITY | 3;
|
||||
case ActivityKind.TYPE_EXERCISE:
|
||||
// fitness_equipment
|
||||
return RAW_TYPE_KIND_ACTIVITY | 4;
|
||||
case ActivityKind.TYPE_SWIMMING:
|
||||
// swimming
|
||||
return RAW_TYPE_KIND_ACTIVITY | 5;
|
||||
case ActivityKind.TYPE_WALKING:
|
||||
// walking
|
||||
return RAW_TYPE_KIND_ACTIVITY | 6;
|
||||
case ActivityKind.TYPE_LIGHT_SLEEP:
|
||||
return RAW_TYPE_KIND_SLEEP | 1;
|
||||
case ActivityKind.TYPE_DEEP_SLEEP:
|
||||
//noinspection PointlessBitwiseExpression
|
||||
return RAW_TYPE_KIND_SLEEP | 0;
|
||||
default:
|
||||
if ((activityKind & ActivityKind.TYPE_SWIMMING) != 0) return RAW_TYPE_KIND_ACTIVITY | 5;
|
||||
if ((activityKind & ActivityKind.TYPE_CYCLING) != 0) return RAW_TYPE_KIND_ACTIVITY | 2;
|
||||
if ((activityKind & ActivityKind.TYPE_RUNNING) != 0) return RAW_TYPE_KIND_ACTIVITY | 1;
|
||||
if ((activityKind & ActivityKind.TYPE_EXERCISE) != 0) return RAW_TYPE_KIND_ACTIVITY | 4;
|
||||
if ((activityKind & ActivityKind.TYPE_WALKING) != 0) return RAW_TYPE_KIND_ACTIVITY | 6;
|
||||
if ((activityKind & ActivityKind.TYPE_SLEEP) != 0) return RAW_TYPE_KIND_SLEEP | 1;
|
||||
if ((activityKind & ActivityKind.TYPE_ACTIVITY) != 0) {
|
||||
//noinspection PointlessBitwiseExpression
|
||||
return RAW_TYPE_KIND_ACTIVITY | 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float normalizeIntensity(int rawIntensity) {
|
||||
return rawIntensity / 255.0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VivomoveHrActivitySample createActivitySample() {
|
||||
return new VivomoveHrActivitySample();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractDao<VivomoveHrActivitySample, ?> getSampleDao() {
|
||||
return getSession().getVivomoveHrActivitySampleDao();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected Property getRawKindSampleProperty() {
|
||||
return VivomoveHrActivitySampleDao.Properties.RawKind;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Property getTimestampSampleProperty() {
|
||||
return VivomoveHrActivitySampleDao.Properties.Timestamp;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Property getDeviceIdentifierSampleProperty() {
|
||||
return VivomoveHrActivitySampleDao.Properties.DeviceId;
|
||||
}
|
||||
|
||||
public static String rawKindToString(int rawType) {
|
||||
if (rawType == RAW_NOT_WORN) {
|
||||
return "not worn";
|
||||
}
|
||||
|
||||
switch (rawType & RAW_TYPE_KIND_MASK) {
|
||||
case RAW_TYPE_KIND_ACTIVITY:
|
||||
return activityTypeToString(rawType & ~RAW_TYPE_KIND_MASK);
|
||||
case RAW_TYPE_KIND_SLEEP:
|
||||
return sleepTypeToString(rawType & ~RAW_TYPE_KIND_MASK);
|
||||
default:
|
||||
// ???
|
||||
return "unknown " + rawType;
|
||||
}
|
||||
}
|
||||
|
||||
private static String activityTypeToString(int rawType) {
|
||||
switch (rawType) {
|
||||
case 0:
|
||||
return "generic";
|
||||
case 1:
|
||||
return "running";
|
||||
case 2:
|
||||
return "cycling";
|
||||
case 3:
|
||||
return "transition";
|
||||
case 4:
|
||||
return "fitness equipment";
|
||||
case 5:
|
||||
return "swimming";
|
||||
case 6:
|
||||
return "walking";
|
||||
case 8:
|
||||
return "sedentary";
|
||||
default:
|
||||
return "unknown activity " + rawType;
|
||||
}
|
||||
}
|
||||
|
||||
private static String sleepTypeToString(int rawType) {
|
||||
switch (rawType) {
|
||||
case 0:
|
||||
return "deep sleep";
|
||||
case 1:
|
||||
return "light sleep";
|
||||
case 2:
|
||||
// awake
|
||||
return "awake";
|
||||
case 3:
|
||||
// more_awake
|
||||
return "more awake";
|
||||
default:
|
||||
return "unknown sleep " + rawType;
|
||||
}
|
||||
}
|
||||
}
|
@ -106,6 +106,7 @@ public enum DeviceType {
|
||||
FITPRO(230, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_fitpro),
|
||||
ITAG(250, R.drawable.ic_device_itag, R.drawable.ic_device_itag_disabled, R.string.devicetype_itag),
|
||||
NUTMINI(251, R.drawable.ic_device_itag, R.drawable.ic_device_itag_disabled, R.string.devicetype_nut_mini),
|
||||
VIVOMOVE_HR(260, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_vivomove_hr),
|
||||
VIBRATISSIMO(300, R.drawable.ic_device_lovetoy, R.drawable.ic_device_lovetoy_disabled, R.string.devicetype_vibratissimo),
|
||||
SONY_SWR12(310, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_sonyswr12),
|
||||
LIVEVIEW(320, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_liveview),
|
||||
|
@ -27,6 +27,7 @@ import android.bluetooth.BluetoothDevice;
|
||||
import android.content.Context;
|
||||
import android.widget.Toast;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.vivomovehr.VivomoveHrCoordinator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -373,6 +374,7 @@ public class DeviceHelper {
|
||||
result.add(new SuperCarsCoordinator());
|
||||
result.add(new AsteroidOSDeviceCoordinator());
|
||||
result.add(new SoFlowCoordinator());
|
||||
result.add(new VivomoveHrCoordinator());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -1269,6 +1269,7 @@
|
||||
<string name="devicetype_amazfit_gts2e">Amazfit GTS 2e</string>
|
||||
<string name="devicetype_amazfit_x">Amazfit X</string>
|
||||
<string name="devicetype_zepp_e">Zepp E</string>
|
||||
<string name="devicetype_vivomove_hr">Garmin Vivomove HR</string>
|
||||
<string name="devicetype_vibratissimo">Vibratissimo</string>
|
||||
<string name="devicetype_um25">UM-25</string>
|
||||
<string name="devicetype_liveview">LiveView</string>
|
||||
|
Loading…
Reference in New Issue
Block a user