Merge remote-tracking branch 'origin/fossil-q-hr' into fossil-q-hr
@ -70,7 +70,7 @@ public class GBDaoGenerator {
|
|||||||
addXWatchActivitySample(schema, user, device);
|
addXWatchActivitySample(schema, user, device);
|
||||||
addZeTimeActivitySample(schema, user, device);
|
addZeTimeActivitySample(schema, user, device);
|
||||||
addID115ActivitySample(schema, user, device);
|
addID115ActivitySample(schema, user, device);
|
||||||
|
addJYouActivitySample(schema, user, device);
|
||||||
addCalendarSyncState(schema, device);
|
addCalendarSyncState(schema, device);
|
||||||
addAlarms(schema, user, device);
|
addAlarms(schema, user, device);
|
||||||
|
|
||||||
@ -328,6 +328,19 @@ public class GBDaoGenerator {
|
|||||||
return activitySample;
|
return activitySample;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Entity addJYouActivitySample(Schema schema, Entity user, Entity device) {
|
||||||
|
Entity activitySample = addEntity(schema, "JYouActivitySample");
|
||||||
|
activitySample.implementsSerializable();
|
||||||
|
addCommonActivitySampleProperties("AbstractActivitySample", activitySample, user, device);
|
||||||
|
activitySample.addIntProperty(SAMPLE_STEPS).notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||||
|
activitySample.addIntProperty(SAMPLE_RAW_KIND).notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||||
|
activitySample.addIntProperty("caloriesBurnt");
|
||||||
|
activitySample.addIntProperty("distanceMeters");
|
||||||
|
activitySample.addIntProperty("activeTimeMinutes");
|
||||||
|
addHeartRateProperties(activitySample);
|
||||||
|
return activitySample;
|
||||||
|
}
|
||||||
|
|
||||||
private static void addCommonActivitySampleProperties(String superClass, Entity activitySample, Entity user, Entity device) {
|
private static void addCommonActivitySampleProperties(String superClass, Entity activitySample, Entity user, Entity device) {
|
||||||
activitySample.setSuperclass(superClass);
|
activitySample.setSuperclass(superClass);
|
||||||
activitySample.addImport(MAIN_PACKAGE + ".devices.SampleProvider");
|
activitySample.addImport(MAIN_PACKAGE + ".devices.SampleProvider");
|
||||||
|
@ -55,6 +55,7 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
|
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
|
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||||
|
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.GBApplication.getContext;
|
import static nodomain.freeyourgadget.gadgetbridge.GBApplication.getContext;
|
||||||
@ -198,7 +199,9 @@ public class HPlusCoordinator extends AbstractDeviceCoordinator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static byte getTimeMode(String deviceAddress) {
|
public static byte getTimeMode(String deviceAddress) {
|
||||||
String tmode = GBApplication.getDeviceSpecificSharedPrefs(deviceAddress).getString(DeviceSettingsPreferenceConst.PREF_TIMEFORMAT, "24h");
|
GBPrefs gbPrefs = new GBPrefs(new Prefs(GBApplication.getDeviceSpecificSharedPrefs(deviceAddress)));
|
||||||
|
|
||||||
|
String tmode = gbPrefs.getTimeFormat();
|
||||||
|
|
||||||
if ("24h".equals(tmode)) {
|
if ("24h".equals(tmode)) {
|
||||||
return HPlusConstants.ARG_TIMEMODE_24H;
|
return HPlusConstants.ARG_TIMEMODE_24H;
|
||||||
|
@ -81,6 +81,7 @@ public class AmazfitBipCoordinator extends HuamiCoordinator {
|
|||||||
public int[] getSupportedDeviceSpecificSettings(GBDevice device) {
|
public int[] getSupportedDeviceSpecificSettings(GBDevice device) {
|
||||||
return new int[]{
|
return new int[]{
|
||||||
R.xml.devicesettings_amazfitbip,
|
R.xml.devicesettings_amazfitbip,
|
||||||
|
R.xml.devicesettings_timeformat,
|
||||||
R.xml.devicesettings_wearlocation,
|
R.xml.devicesettings_wearlocation,
|
||||||
R.xml.devicesettings_custom_emoji_font,
|
R.xml.devicesettings_custom_emoji_font,
|
||||||
R.xml.devicesettings_liftwrist_display,
|
R.xml.devicesettings_liftwrist_display,
|
||||||
|
@ -85,6 +85,7 @@ public class AmazfitCorCoordinator extends HuamiCoordinator {
|
|||||||
return new int[]{
|
return new int[]{
|
||||||
R.xml.devicesettings_amazfitcor,
|
R.xml.devicesettings_amazfitcor,
|
||||||
R.xml.devicesettings_wearlocation,
|
R.xml.devicesettings_wearlocation,
|
||||||
|
R.xml.devicesettings_timeformat,
|
||||||
R.xml.devicesettings_custom_emoji_font,
|
R.xml.devicesettings_custom_emoji_font,
|
||||||
R.xml.devicesettings_liftwrist_display,
|
R.xml.devicesettings_liftwrist_display,
|
||||||
R.xml.devicesettings_disconnectnotification,
|
R.xml.devicesettings_disconnectnotification,
|
||||||
|
@ -87,6 +87,7 @@ public class AmazfitCor2Coordinator extends HuamiCoordinator {
|
|||||||
return new int[]{
|
return new int[]{
|
||||||
R.xml.devicesettings_amazfitcor,
|
R.xml.devicesettings_amazfitcor,
|
||||||
R.xml.devicesettings_wearlocation,
|
R.xml.devicesettings_wearlocation,
|
||||||
|
R.xml.devicesettings_timeformat,
|
||||||
R.xml.devicesettings_custom_emoji_font,
|
R.xml.devicesettings_custom_emoji_font,
|
||||||
R.xml.devicesettings_liftwrist_display,
|
R.xml.devicesettings_liftwrist_display,
|
||||||
R.xml.devicesettings_disconnectnotification,
|
R.xml.devicesettings_disconnectnotification,
|
||||||
|
@ -90,6 +90,7 @@ public class AmazfitGTRCoordinator extends HuamiCoordinator {
|
|||||||
return new int[]{
|
return new int[]{
|
||||||
R.xml.devicesettings_amazfitgtr,
|
R.xml.devicesettings_amazfitgtr,
|
||||||
R.xml.devicesettings_wearlocation,
|
R.xml.devicesettings_wearlocation,
|
||||||
|
R.xml.devicesettings_timeformat,
|
||||||
R.xml.devicesettings_liftwrist_display,
|
R.xml.devicesettings_liftwrist_display,
|
||||||
R.xml.devicesettings_disconnectnotification,
|
R.xml.devicesettings_disconnectnotification,
|
||||||
R.xml.devicesettings_expose_hr_thirdparty,
|
R.xml.devicesettings_expose_hr_thirdparty,
|
||||||
|
@ -90,6 +90,7 @@ public class AmazfitGTSCoordinator extends HuamiCoordinator {
|
|||||||
return new int[]{
|
return new int[]{
|
||||||
R.xml.devicesettings_amazfitgtr,
|
R.xml.devicesettings_amazfitgtr,
|
||||||
R.xml.devicesettings_wearlocation,
|
R.xml.devicesettings_wearlocation,
|
||||||
|
R.xml.devicesettings_timeformat,
|
||||||
R.xml.devicesettings_liftwrist_display,
|
R.xml.devicesettings_liftwrist_display,
|
||||||
R.xml.devicesettings_disconnectnotification,
|
R.xml.devicesettings_disconnectnotification,
|
||||||
R.xml.devicesettings_expose_hr_thirdparty,
|
R.xml.devicesettings_expose_hr_thirdparty,
|
||||||
|
@ -80,6 +80,7 @@ public class MiBand2Coordinator extends HuamiCoordinator {
|
|||||||
return new int[]{
|
return new int[]{
|
||||||
R.xml.devicesettings_miband2,
|
R.xml.devicesettings_miband2,
|
||||||
R.xml.devicesettings_wearlocation,
|
R.xml.devicesettings_wearlocation,
|
||||||
|
R.xml.devicesettings_timeformat,
|
||||||
R.xml.devicesettings_donotdisturb_withauto,
|
R.xml.devicesettings_donotdisturb_withauto,
|
||||||
R.xml.devicesettings_liftwrist_display,
|
R.xml.devicesettings_liftwrist_display,
|
||||||
R.xml.devicesettings_rotatewrist_cycleinfo,
|
R.xml.devicesettings_rotatewrist_cycleinfo,
|
||||||
|
@ -104,6 +104,7 @@ public class MiBand3Coordinator extends HuamiCoordinator {
|
|||||||
return new int[]{
|
return new int[]{
|
||||||
R.xml.devicesettings_miband3,
|
R.xml.devicesettings_miband3,
|
||||||
R.xml.devicesettings_wearlocation,
|
R.xml.devicesettings_wearlocation,
|
||||||
|
R.xml.devicesettings_timeformat,
|
||||||
R.xml.devicesettings_dateformat,
|
R.xml.devicesettings_dateformat,
|
||||||
R.xml.devicesettings_nightmode,
|
R.xml.devicesettings_nightmode,
|
||||||
R.xml.devicesettings_donotdisturb_withauto,
|
R.xml.devicesettings_donotdisturb_withauto,
|
||||||
|
@ -91,6 +91,7 @@ public class MiBand4Coordinator extends HuamiCoordinator {
|
|||||||
R.xml.devicesettings_miband3,
|
R.xml.devicesettings_miband3,
|
||||||
R.xml.devicesettings_wearlocation,
|
R.xml.devicesettings_wearlocation,
|
||||||
R.xml.devicesettings_custom_emoji_font,
|
R.xml.devicesettings_custom_emoji_font,
|
||||||
|
R.xml.devicesettings_timeformat,
|
||||||
R.xml.devicesettings_dateformat,
|
R.xml.devicesettings_dateformat,
|
||||||
R.xml.devicesettings_nightmode,
|
R.xml.devicesettings_nightmode,
|
||||||
R.xml.devicesettings_liftwrist_display,
|
R.xml.devicesettings_liftwrist_display,
|
||||||
|
@ -36,12 +36,17 @@ public final class JYouConstants {
|
|||||||
public static final byte CMD_SET_SLEEP_TIME = 0x27;
|
public static final byte CMD_SET_SLEEP_TIME = 0x27;
|
||||||
public static final byte CMD_SET_DND_SETTINGS = 0x39;
|
public static final byte CMD_SET_DND_SETTINGS = 0x39;
|
||||||
public static final byte CMD_SET_INACTIVITY_WARNING_TIME = 0x24;
|
public static final byte CMD_SET_INACTIVITY_WARNING_TIME = 0x24;
|
||||||
|
|
||||||
public static final byte CMD_ACTION_HEARTRATE_SWITCH = 0x0D;
|
public static final byte CMD_ACTION_HEARTRATE_SWITCH = 0x0D;
|
||||||
public static final byte CMD_ACTION_SHOW_NOTIFICATION = 0x2C;
|
public static final byte CMD_ACTION_SHOW_NOTIFICATION = 0x2C;
|
||||||
public static final byte CMD_ACTION_REBOOT_DEVICE = 0x0E;
|
public static final byte CMD_ACTION_REBOOT_DEVICE = 0x0E;
|
||||||
|
|
||||||
public static final byte RECEIVE_BATTERY_LEVEL = (byte)0xF7;
|
public static final byte RECEIVE_HISTORY_SLEEP_COUNT = 0x32;
|
||||||
|
public static final byte RECEIVE_BLOOD_PRESSURE = (byte) 0xE8;
|
||||||
|
public static final byte RECEIVE_WATCH_MAC = (byte)0xEC;
|
||||||
|
public static final byte RECEIVE_GET_PHOTO = (byte)0xF3;
|
||||||
public static final byte RECEIVE_DEVICE_INFO = (byte)0xF6;
|
public static final byte RECEIVE_DEVICE_INFO = (byte)0xF6;
|
||||||
|
public static final byte RECEIVE_BATTERY_LEVEL = (byte)0xF7;
|
||||||
public static final byte RECEIVE_STEPS_DATA = (byte)0xF9;
|
public static final byte RECEIVE_STEPS_DATA = (byte)0xF9;
|
||||||
public static final byte RECEIVE_HEARTRATE = (byte)0xFC;
|
public static final byte RECEIVE_HEARTRATE = (byte)0xFC;
|
||||||
|
|
||||||
|
@ -0,0 +1,70 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.jyou;
|
||||||
|
|
||||||
|
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.JYouActivitySample;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.JYouActivitySampleDao;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
|
|
||||||
|
public class JYouSampleProvider extends AbstractSampleProvider<JYouActivitySample> {
|
||||||
|
|
||||||
|
public static final int TYPE_ACTIVITY = -1;
|
||||||
|
private final float movementDivisor = 6000.0f;
|
||||||
|
private GBDevice mDevice;
|
||||||
|
private DaoSession mSession;
|
||||||
|
|
||||||
|
public JYouSampleProvider(GBDevice device, DaoSession session) {
|
||||||
|
super(device, session);
|
||||||
|
|
||||||
|
mSession = session;
|
||||||
|
mDevice = device;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int normalizeType(int rawType) {
|
||||||
|
return rawType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int toRawActivityKind(int activityKind) {
|
||||||
|
return activityKind;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float normalizeIntensity(int rawIntensity) {
|
||||||
|
return rawIntensity/movementDivisor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JYouActivitySample createActivitySample() {
|
||||||
|
return new JYouActivitySample();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AbstractDao<JYouActivitySample, ?> getSampleDao() {
|
||||||
|
return getSession().getJYouActivitySampleDao();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
protected Property getRawKindSampleProperty() {
|
||||||
|
return JYouActivitySampleDao.Properties.RawKind;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
protected Property getTimestampSampleProperty() {
|
||||||
|
return JYouActivitySampleDao.Properties.Timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
protected Property getDeviceIdentifierSampleProperty() {
|
||||||
|
return JYouActivitySampleDao.Properties.DeviceId;
|
||||||
|
}
|
||||||
|
}
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
You should have received a copy of the GNU Affero General Public License
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
package nodomain.freeyourgadget.gadgetbridge.devices.jyou;
|
package nodomain.freeyourgadget.gadgetbridge.devices.jyou.TeclastH30;
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
@ -38,6 +38,7 @@ import nodomain.freeyourgadget.gadgetbridge.GBException;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractDeviceCoordinator;
|
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractDeviceCoordinator;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
|
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
|
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.jyou.JYouConstants;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
@ -0,0 +1,132 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.jyou.y5;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.Uri;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import de.greenrobot.dao.query.QueryBuilder;
|
||||||
|
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.devices.jyou.JYouSampleProvider;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.JYouActivitySampleDao;
|
||||||
|
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 Y5Coordinator extends AbstractDeviceCoordinator {
|
||||||
|
@Override
|
||||||
|
protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device device, @NonNull DaoSession session) throws GBException {
|
||||||
|
Long deviceId = device.getId();
|
||||||
|
QueryBuilder<?> qb = session.getJYouActivitySampleDao().queryBuilder();
|
||||||
|
qb.where(JYouActivitySampleDao.Properties.DeviceId.eq(deviceId)).buildDelete().executeDeleteWithoutDetachingEntities();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public DeviceType getSupportedType(GBDeviceCandidate candidate) {
|
||||||
|
try {
|
||||||
|
String name = candidate.getDevice().getName();
|
||||||
|
if (name != null) {
|
||||||
|
if (name.contains("Y5")) {
|
||||||
|
return DeviceType.Y5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
ex.getLocalizedMessage();
|
||||||
|
}
|
||||||
|
return DeviceType.UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DeviceType getDeviceType() {
|
||||||
|
return DeviceType.Y5;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 JYouSampleProvider(device, session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InstallHandler findInstallHandler(Uri uri, Context context) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsScreenshots() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAlarmSlotCount() {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsSmartWakeup(GBDevice device) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsHeartRateMeasurement(GBDevice device) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getManufacturer() {
|
||||||
|
return "Y5";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsAppsManagement() {
|
||||||
|
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 false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsFindDevice() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -35,6 +35,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import de.greenrobot.dao.query.QueryBuilder;
|
import de.greenrobot.dao.query.QueryBuilder;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.GBException;
|
import nodomain.freeyourgadget.gadgetbridge.GBException;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
|
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
|
||||||
@ -48,6 +49,8 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
|
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||||
|
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.GBApplication.getContext;
|
import static nodomain.freeyourgadget.gadgetbridge.GBApplication.getContext;
|
||||||
|
|
||||||
@ -75,7 +78,9 @@ public class MakibesHR3Coordinator extends AbstractDeviceCoordinator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static byte getTimeMode(SharedPreferences sharedPrefs) {
|
public static byte getTimeMode(SharedPreferences sharedPrefs) {
|
||||||
String timeMode = sharedPrefs.getString(DeviceSettingsPreferenceConst.PREF_TIMEFORMAT, getContext().getString(R.string.p_timeformat_24h));
|
GBPrefs gbPrefs = new GBPrefs(new Prefs(sharedPrefs));
|
||||||
|
|
||||||
|
String timeMode = gbPrefs.getTimeFormat();
|
||||||
|
|
||||||
if (timeMode.equals(getContext().getString(R.string.p_timeformat_24h))) {
|
if (timeMode.equals(getContext().getString(R.string.p_timeformat_24h))) {
|
||||||
return MakibesHR3Constants.ARG_SET_TIMEMODE_24H;
|
return MakibesHR3Constants.ARG_SET_TIMEMODE_24H;
|
||||||
|
@ -63,6 +63,7 @@ public class AppNotificationType extends HashMap<String, NotificationType> {
|
|||||||
|
|
||||||
// Conversations
|
// Conversations
|
||||||
put("eu.siacs.conversations", NotificationType.CONVERSATIONS);
|
put("eu.siacs.conversations", NotificationType.CONVERSATIONS);
|
||||||
|
put("de.pixart.messenger", NotificationType.CONVERSATIONS);
|
||||||
|
|
||||||
// Riot
|
// Riot
|
||||||
put("im.vector.alpha", NotificationType.RIOT);
|
put("im.vector.alpha", NotificationType.RIOT);
|
||||||
|
@ -43,7 +43,6 @@ public enum DeviceType {
|
|||||||
AMAZFITBIP_LITE(17, R.drawable.ic_device_hplus, R.drawable.ic_device_hplus_disabled, R.string.devicetype_amazfit_bip_lite),
|
AMAZFITBIP_LITE(17, R.drawable.ic_device_hplus, R.drawable.ic_device_hplus_disabled, R.string.devicetype_amazfit_bip_lite),
|
||||||
AMAZFITGTR(18, R.drawable.ic_device_hplus, R.drawable.ic_device_hplus_disabled, R.string.devicetype_amazfit_gtr),
|
AMAZFITGTR(18, R.drawable.ic_device_hplus, R.drawable.ic_device_hplus_disabled, R.string.devicetype_amazfit_gtr),
|
||||||
AMAZFITGTS(19, R.drawable.ic_device_hplus, R.drawable.ic_device_hplus_disabled, R.string.devicetype_amazfit_gts),
|
AMAZFITGTS(19, R.drawable.ic_device_hplus, R.drawable.ic_device_hplus_disabled, R.string.devicetype_amazfit_gts),
|
||||||
VIBRATISSIMO(20, R.drawable.ic_device_lovetoy, R.drawable.ic_device_lovetoy_disabled, R.string.devicetype_vibratissimo),
|
|
||||||
LIVEVIEW(30, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_liveview),
|
LIVEVIEW(30, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_liveview),
|
||||||
HPLUS(40, R.drawable.ic_device_hplus, R.drawable.ic_device_hplus_disabled, R.string.devicetype_hplus),
|
HPLUS(40, R.drawable.ic_device_hplus, R.drawable.ic_device_hplus_disabled, R.string.devicetype_hplus),
|
||||||
MAKIBESF68(41, R.drawable.ic_device_hplus, R.drawable.ic_device_hplus_disabled, R.string.devicetype_makibes_f68),
|
MAKIBESF68(41, R.drawable.ic_device_hplus, R.drawable.ic_device_hplus_disabled, R.string.devicetype_makibes_f68),
|
||||||
@ -51,6 +50,7 @@ public enum DeviceType {
|
|||||||
Q8(43, R.drawable.ic_device_hplus, R.drawable.ic_device_hplus_disabled, R.string.devicetype_q8),
|
Q8(43, R.drawable.ic_device_hplus, R.drawable.ic_device_hplus_disabled, R.string.devicetype_q8),
|
||||||
NO1F1(50, R.drawable.ic_device_hplus, R.drawable.ic_device_hplus_disabled, R.string.devicetype_no1_f1),
|
NO1F1(50, R.drawable.ic_device_hplus, R.drawable.ic_device_hplus_disabled, R.string.devicetype_no1_f1),
|
||||||
TECLASTH30(60, R.drawable.ic_device_h30_h10, R.drawable.ic_device_h30_h10_disabled, R.string.devicetype_teclast_h30),
|
TECLASTH30(60, R.drawable.ic_device_h30_h10, R.drawable.ic_device_h30_h10_disabled, R.string.devicetype_teclast_h30),
|
||||||
|
Y5(61, R.drawable.ic_device_h30_h10, R.drawable.ic_device_roidmi_disabled, R.string.devicetype_y5),
|
||||||
XWATCH(70, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_xwatch),
|
XWATCH(70, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_xwatch),
|
||||||
FOSSILQHYBRID(80, R.drawable.ic_device_zetime, R.drawable.ic_device_zetime_disabled, R.string.devicetype_qhybrid),
|
FOSSILQHYBRID(80, R.drawable.ic_device_zetime, R.drawable.ic_device_zetime_disabled, R.string.devicetype_qhybrid),
|
||||||
ZETIME(80, R.drawable.ic_device_zetime, R.drawable.ic_device_zetime_disabled, R.string.devicetype_mykronoz_zetime),
|
ZETIME(80, R.drawable.ic_device_zetime, R.drawable.ic_device_zetime_disabled, R.string.devicetype_mykronoz_zetime),
|
||||||
@ -64,6 +64,7 @@ public enum DeviceType {
|
|||||||
MAKIBESHR3(150, R.drawable.ic_device_default, R.drawable.ic_device_hplus_disabled, R.string.devicetype_makibes_hr3),
|
MAKIBESHR3(150, R.drawable.ic_device_default, R.drawable.ic_device_hplus_disabled, R.string.devicetype_makibes_hr3),
|
||||||
BANGLEJS(160, R.drawable.ic_device_zetime, R.drawable.ic_device_zetime_disabled, R.string.devicetype_banglejs),
|
BANGLEJS(160, R.drawable.ic_device_zetime, R.drawable.ic_device_zetime_disabled, R.string.devicetype_banglejs),
|
||||||
MIJIA_LYWSD02(200, R.drawable.ic_device_pebble, R.drawable.ic_device_pebble_disabled, R.string.devicetype_mijia_lywsd02),
|
MIJIA_LYWSD02(200, R.drawable.ic_device_pebble, R.drawable.ic_device_pebble_disabled, R.string.devicetype_mijia_lywsd02),
|
||||||
|
VIBRATISSIMO(300, R.drawable.ic_device_lovetoy, R.drawable.ic_device_lovetoy_disabled, R.string.devicetype_vibratissimo),
|
||||||
TEST(1000, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_test);
|
TEST(1000, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_test);
|
||||||
|
|
||||||
private final int key;
|
private final int key;
|
||||||
|
@ -45,7 +45,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.miband3.MiBand
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.miband4.MiBand4Support;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.miband4.MiBand4Support;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.id115.ID115Support;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.id115.ID115Support;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.jyou.BFH16DeviceSupport;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.jyou.BFH16DeviceSupport;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.jyou.TeclastH30Support;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.jyou.TeclastH30.TeclastH30Support;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.liveview.LiveviewSupport;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.liveview.LiveviewSupport;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.makibeshr3.MakibesHR3DeviceSupport;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.makibeshr3.MakibesHR3DeviceSupport;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.MiBandSupport;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.MiBandSupport;
|
||||||
@ -57,6 +57,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSuppo
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.roidmi.RoidmiSupport;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.roidmi.RoidmiSupport;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.vibratissimo.VibratissimoSupport;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.vibratissimo.VibratissimoSupport;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.watch9.Watch9DeviceSupport;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.watch9.Watch9DeviceSupport;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.jyou.y5.Y5Support;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.xwatch.XWatchSupport;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.xwatch.XWatchSupport;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.zetime.ZeTimeDeviceSupport;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.zetime.ZeTimeDeviceSupport;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
@ -203,6 +204,9 @@ public class DeviceSupportFactory {
|
|||||||
case ROIDMI3:
|
case ROIDMI3:
|
||||||
deviceSupport = new ServiceDeviceSupport(new RoidmiSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
deviceSupport = new ServiceDeviceSupport(new RoidmiSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||||
break;
|
break;
|
||||||
|
case Y5:
|
||||||
|
deviceSupport = new ServiceDeviceSupport(new Y5Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||||
|
break;
|
||||||
case CASIOGB6900:
|
case CASIOGB6900:
|
||||||
deviceSupport = new ServiceDeviceSupport(new CasioGB6900DeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
deviceSupport = new ServiceDeviceSupport(new CasioGB6900DeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||||
break;
|
break;
|
||||||
|
@ -130,6 +130,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.util.AlarmUtils;
|
import nodomain.freeyourgadget.gadgetbridge.util.AlarmUtils;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.NotificationUtils;
|
import nodomain.freeyourgadget.gadgetbridge.util.NotificationUtils;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
||||||
@ -1700,6 +1701,9 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
|
|||||||
case MiBandConst.PREF_SWIPE_UNLOCK:
|
case MiBandConst.PREF_SWIPE_UNLOCK:
|
||||||
setBandScreenUnlock(builder);
|
setBandScreenUnlock(builder);
|
||||||
break;
|
break;
|
||||||
|
case DeviceSettingsPreferenceConst.PREF_TIMEFORMAT:
|
||||||
|
setTimeFormat(builder);
|
||||||
|
break;
|
||||||
case DeviceSettingsPreferenceConst.PREF_DATEFORMAT:
|
case DeviceSettingsPreferenceConst.PREF_DATEFORMAT:
|
||||||
setDateFormat(builder);
|
setDateFormat(builder);
|
||||||
break;
|
break;
|
||||||
@ -1952,9 +1956,11 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private HuamiSupport setTimeFormat(TransactionBuilder builder) {
|
private HuamiSupport setTimeFormat(TransactionBuilder builder) {
|
||||||
boolean is24Format = DateFormat.is24HourFormat(getContext());
|
GBPrefs gbPrefs = new GBPrefs(new Prefs(GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress())));
|
||||||
LOG.info("Setting 24h time format to " + is24Format);
|
String timeFormat = gbPrefs.getTimeFormat();
|
||||||
if (is24Format) {
|
|
||||||
|
LOG.info("Setting time format to " + timeFormat);
|
||||||
|
if (timeFormat.equals("24h")) {
|
||||||
builder.write(getCharacteristic(HuamiService.UUID_CHARACTERISTIC_3_CONFIGURATION), HuamiService.DATEFORMAT_TIME_24_HOURS);
|
builder.write(getCharacteristic(HuamiService.UUID_CHARACTERISTIC_3_CONFIGURATION), HuamiService.DATEFORMAT_TIME_24_HOURS);
|
||||||
} else {
|
} else {
|
||||||
builder.write(getCharacteristic(HuamiService.UUID_CHARACTERISTIC_3_CONFIGURATION), HuamiService.DATEFORMAT_TIME_12_HOURS);
|
builder.write(getCharacteristic(HuamiService.UUID_CHARACTERISTIC_3_CONFIGURATION), HuamiService.DATEFORMAT_TIME_12_HOURS);
|
||||||
|
@ -0,0 +1,65 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.jyou;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @author Pavel Elagin <elagin.pasha@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
|
||||||
|
|
||||||
|
public class JYouDataRecord {
|
||||||
|
public final static int TYPE_UNKNOWN = 0;
|
||||||
|
public final static int TYPE_SLEEP = 100;
|
||||||
|
public final static int TYPE_DAY_SUMMARY = 101;
|
||||||
|
public final static int TYPE_DAY_SLOT = 102;
|
||||||
|
public final static int TYPE_REALTIME = 103;
|
||||||
|
|
||||||
|
public int type = TYPE_UNKNOWN;
|
||||||
|
public int activityKind = ActivityKind.TYPE_UNKNOWN;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time of this record in seconds
|
||||||
|
*/
|
||||||
|
public int timestamp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raw data as sent from the device
|
||||||
|
*/
|
||||||
|
public byte[] rawData;
|
||||||
|
|
||||||
|
protected JYouDataRecord(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected JYouDataRecord(byte[] data, int type){
|
||||||
|
this.rawData = data;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getRawData() {
|
||||||
|
|
||||||
|
return rawData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RecordInterval {
|
||||||
|
/**
|
||||||
|
* Start time of this interval in seconds
|
||||||
|
*/
|
||||||
|
public int timestampFrom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End time of this interval in seconds
|
||||||
|
*/
|
||||||
|
public int timestampTo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of activity {@link ActivityKind}
|
||||||
|
*/
|
||||||
|
public int activityKind;
|
||||||
|
|
||||||
|
RecordInterval(int timestampFrom, int timestampTo, int activityKind) {
|
||||||
|
this.timestampFrom = timestampFrom;
|
||||||
|
this.timestampTo = timestampTo;
|
||||||
|
this.activityKind = activityKind;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -23,7 +23,6 @@ import android.net.Uri;
|
|||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
@ -50,29 +49,32 @@ import nodomain.freeyourgadget.gadgetbridge.util.AlarmUtils;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
||||||
|
|
||||||
public class TeclastH30Support extends AbstractBTLEDeviceSupport {
|
public class JYouSupport extends AbstractBTLEDeviceSupport {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(TeclastH30Support.class);
|
private Logger logger;
|
||||||
|
|
||||||
public BluetoothGattCharacteristic ctrlCharacteristic = null;
|
protected BluetoothGattCharacteristic ctrlCharacteristic = null;
|
||||||
public BluetoothGattCharacteristic measureCharacteristic = null;
|
|
||||||
|
|
||||||
private final GBDeviceEventVersionInfo versionCmd = new GBDeviceEventVersionInfo();
|
protected final GBDeviceEventVersionInfo versionCmd = new GBDeviceEventVersionInfo();
|
||||||
private final GBDeviceEventBatteryInfo batteryCmd = new GBDeviceEventBatteryInfo();
|
protected final GBDeviceEventBatteryInfo batteryCmd = new GBDeviceEventBatteryInfo();
|
||||||
|
|
||||||
public TeclastH30Support() {
|
public JYouSupport(Logger logger) {
|
||||||
super(LOG);
|
super(logger);
|
||||||
|
this.logger = logger;
|
||||||
|
if (logger == null) {
|
||||||
|
throw new IllegalArgumentException("logger must not be null");
|
||||||
|
}
|
||||||
addSupportedService(JYouConstants.UUID_SERVICE_JYOU);
|
addSupportedService(JYouConstants.UUID_SERVICE_JYOU);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected TransactionBuilder initializeDevice(TransactionBuilder builder) {
|
protected TransactionBuilder initializeDevice(TransactionBuilder builder) {
|
||||||
LOG.info("Initializing");
|
logger.info("Initializing");
|
||||||
|
|
||||||
gbDevice.setState(GBDevice.State.INITIALIZING);
|
gbDevice.setState(GBDevice.State.INITIALIZING);
|
||||||
gbDevice.sendDeviceUpdateIntent(getContext());
|
gbDevice.sendDeviceUpdateIntent(getContext());
|
||||||
|
|
||||||
measureCharacteristic = getCharacteristic(JYouConstants.UUID_CHARACTERISTIC_MEASURE);
|
BluetoothGattCharacteristic measureCharacteristic = getCharacteristic(JYouConstants.UUID_CHARACTERISTIC_MEASURE);
|
||||||
ctrlCharacteristic = getCharacteristic(JYouConstants.UUID_CHARACTERISTIC_CONTROL);
|
ctrlCharacteristic = getCharacteristic(JYouConstants.UUID_CHARACTERISTIC_CONTROL);
|
||||||
|
|
||||||
builder.setGattCallback(this);
|
builder.setGattCallback(this);
|
||||||
@ -83,7 +85,7 @@ public class TeclastH30Support extends AbstractBTLEDeviceSupport {
|
|||||||
gbDevice.setState(GBDevice.State.INITIALIZED);
|
gbDevice.setState(GBDevice.State.INITIALIZED);
|
||||||
gbDevice.sendDeviceUpdateIntent(getContext());
|
gbDevice.sendDeviceUpdateIntent(getContext());
|
||||||
|
|
||||||
LOG.info("Initialization Done");
|
logger.info("Initialization Done");
|
||||||
|
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
@ -91,41 +93,10 @@ public class TeclastH30Support extends AbstractBTLEDeviceSupport {
|
|||||||
@Override
|
@Override
|
||||||
public boolean onCharacteristicChanged(BluetoothGatt gatt,
|
public boolean onCharacteristicChanged(BluetoothGatt gatt,
|
||||||
BluetoothGattCharacteristic characteristic) {
|
BluetoothGattCharacteristic characteristic) {
|
||||||
if (super.onCharacteristicChanged(gatt, characteristic)) {
|
return super.onCharacteristicChanged(gatt, characteristic);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UUID characteristicUUID = characteristic.getUuid();
|
protected void syncDateAndTime(TransactionBuilder builder) {
|
||||||
byte[] data = characteristic.getValue();
|
|
||||||
if (data.length == 0)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
switch (data[0]) {
|
|
||||||
case JYouConstants.RECEIVE_DEVICE_INFO:
|
|
||||||
int fwVerNum = data[4] & 0xFF;
|
|
||||||
versionCmd.fwVersion = (fwVerNum / 100) + "." + ((fwVerNum % 100) / 10) + "." + ((fwVerNum % 100) % 10);
|
|
||||||
handleGBDeviceEvent(versionCmd);
|
|
||||||
LOG.info("Firmware version is: " + versionCmd.fwVersion);
|
|
||||||
return true;
|
|
||||||
case JYouConstants.RECEIVE_BATTERY_LEVEL:
|
|
||||||
batteryCmd.level = data[8];
|
|
||||||
handleGBDeviceEvent(batteryCmd);
|
|
||||||
LOG.info("Battery level is: " + batteryCmd.level);
|
|
||||||
return true;
|
|
||||||
case JYouConstants.RECEIVE_STEPS_DATA:
|
|
||||||
int steps = ByteBuffer.wrap(data, 5, 4).getInt();
|
|
||||||
LOG.info("Number of walked steps: " + steps);
|
|
||||||
return true;
|
|
||||||
case JYouConstants.RECEIVE_HEARTRATE:
|
|
||||||
LOG.info("Current heart rate: " + data[8]);
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
LOG.info("Unhandled characteristic change: " + characteristicUUID + " code: " + String.format("0x%1x ...", data[0]));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void syncDateAndTime(TransactionBuilder builder) {
|
|
||||||
Calendar cal = Calendar.getInstance();
|
Calendar cal = Calendar.getInstance();
|
||||||
String strYear = String.valueOf(cal.get(Calendar.YEAR));
|
String strYear = String.valueOf(cal.get(Calendar.YEAR));
|
||||||
byte year1 = (byte)Integer.parseInt(strYear.substring(0, 2));
|
byte year1 = (byte)Integer.parseInt(strYear.substring(0, 2));
|
||||||
@ -144,45 +115,7 @@ public class TeclastH30Support extends AbstractBTLEDeviceSupport {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void syncSettings(TransactionBuilder builder) {
|
protected void syncSettings(TransactionBuilder builder) {
|
||||||
syncDateAndTime(builder);
|
|
||||||
|
|
||||||
// TODO: unhardcode and separate stuff
|
|
||||||
builder.write(ctrlCharacteristic, commandWithChecksum(
|
|
||||||
JYouConstants.CMD_SET_HEARTRATE_WARNING_VALUE, 0, 152
|
|
||||||
));
|
|
||||||
builder.write(ctrlCharacteristic, commandWithChecksum(
|
|
||||||
JYouConstants.CMD_SET_TARGET_STEPS, 0, 10000
|
|
||||||
));
|
|
||||||
builder.write(ctrlCharacteristic, commandWithChecksum(
|
|
||||||
JYouConstants.CMD_GET_STEP_COUNT, 0, 0
|
|
||||||
));
|
|
||||||
builder.write(ctrlCharacteristic, commandWithChecksum(
|
|
||||||
JYouConstants.CMD_GET_SLEEP_TIME, 0, 0
|
|
||||||
));
|
|
||||||
builder.write(ctrlCharacteristic, commandWithChecksum(
|
|
||||||
JYouConstants.CMD_SET_NOON_TIME, 12 * 60 * 60, 14 * 60 * 60 // 12:00 - 14:00
|
|
||||||
));
|
|
||||||
builder.write(ctrlCharacteristic, commandWithChecksum(
|
|
||||||
JYouConstants.CMD_SET_SLEEP_TIME, 21 * 60 * 60, 8 * 60 * 60 // 21:00 - 08:00
|
|
||||||
));
|
|
||||||
builder.write(ctrlCharacteristic, commandWithChecksum(
|
|
||||||
JYouConstants.CMD_SET_INACTIVITY_WARNING_TIME, 0, 0
|
|
||||||
));
|
|
||||||
|
|
||||||
// do not disturb and a couple more features
|
|
||||||
byte dndStartHour = 22;
|
|
||||||
byte dndStartMin = 0;
|
|
||||||
byte dndEndHour = 8;
|
|
||||||
byte dndEndMin = 0;
|
|
||||||
boolean dndToggle = false;
|
|
||||||
boolean vibrationToggle = true;
|
|
||||||
boolean wakeOnRaiseToggle = true;
|
|
||||||
builder.write(ctrlCharacteristic, commandWithChecksum(
|
|
||||||
JYouConstants.CMD_SET_DND_SETTINGS,
|
|
||||||
(dndStartHour << 24) | (dndStartMin << 16) | (dndEndHour << 8) | dndEndMin,
|
|
||||||
((dndToggle ? 0 : 1) << 2) | ((vibrationToggle ? 1 : 0) << 1) | (wakeOnRaiseToggle ? 1 : 0)
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showNotification(byte icon, String title, String message) {
|
private void showNotification(byte icon, String title, String message) {
|
||||||
@ -217,9 +150,9 @@ public class TeclastH30Support extends AbstractBTLEDeviceSupport {
|
|||||||
}
|
}
|
||||||
builder.write(ctrlCharacteristic, currentPacket);
|
builder.write(ctrlCharacteristic, currentPacket);
|
||||||
}
|
}
|
||||||
builder.queue(getQueue());
|
performConnected(builder.getTransaction());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LOG.warn(e.getMessage());
|
logger.warn(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,10 +219,10 @@ public class TeclastH30Support extends AbstractBTLEDeviceSupport {
|
|||||||
alarms.get(i).getEnabled() ? cal.get(Calendar.MINUTE) : -1
|
alarms.get(i).getEnabled() ? cal.get(Calendar.MINUTE) : -1
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
builder.queue(getQueue());
|
performConnected(builder.getTransaction());
|
||||||
GB.toast(getContext(), "Alarm settings applied - do note that the current device does not support day specification", Toast.LENGTH_LONG, GB.INFO);
|
GB.toast(getContext(), "Alarm settings applied - do note that the current device does not support day specification", Toast.LENGTH_LONG, GB.INFO);
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
LOG.warn(e.getMessage());
|
logger.warn(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,18 +231,16 @@ public class TeclastH30Support extends AbstractBTLEDeviceSupport {
|
|||||||
try {
|
try {
|
||||||
TransactionBuilder builder = performInitialized("SetTime");
|
TransactionBuilder builder = performInitialized("SetTime");
|
||||||
syncDateAndTime(builder);
|
syncDateAndTime(builder);
|
||||||
builder.queue(getQueue());
|
performConnected(builder.getTransaction());
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
LOG.warn(e.getMessage());
|
logger.warn(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSetCallState(CallSpec callSpec) {
|
public void onSetCallState(CallSpec callSpec) {
|
||||||
switch (callSpec.command) {
|
if(callSpec.command == CallSpec.CALL_INCOMING) {
|
||||||
case CallSpec.CALL_INCOMING:
|
|
||||||
showNotification(JYouConstants.ICON_CALL, callSpec.name, callSpec.number);
|
showNotification(JYouConstants.ICON_CALL, callSpec.name, callSpec.number);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -375,9 +306,9 @@ public class TeclastH30Support extends AbstractBTLEDeviceSupport {
|
|||||||
builder.write(ctrlCharacteristic, commandWithChecksum(
|
builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||||
JYouConstants.CMD_ACTION_REBOOT_DEVICE, 0, 0
|
JYouConstants.CMD_ACTION_REBOOT_DEVICE, 0, 0
|
||||||
));
|
));
|
||||||
builder.queue(getQueue());
|
performConnected(builder.getTransaction());
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
LOG.warn(e.getMessage());
|
logger.warn(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -388,15 +319,14 @@ public class TeclastH30Support extends AbstractBTLEDeviceSupport {
|
|||||||
builder.write(ctrlCharacteristic, commandWithChecksum(
|
builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||||
JYouConstants.CMD_ACTION_HEARTRATE_SWITCH, 0, 1
|
JYouConstants.CMD_ACTION_HEARTRATE_SWITCH, 0, 1
|
||||||
));
|
));
|
||||||
builder.queue(getQueue());
|
performConnected(builder.getTransaction());
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
LOG.warn(e.getMessage());
|
logger.warn(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnableRealtimeHeartRateMeasurement(boolean enable) {
|
public void onEnableRealtimeHeartRateMeasurement(boolean enable) {
|
||||||
// TODO: test
|
|
||||||
try {
|
try {
|
||||||
TransactionBuilder builder = performInitialized("RealTimeHeartMeasurement");
|
TransactionBuilder builder = performInitialized("RealTimeHeartMeasurement");
|
||||||
builder.write(ctrlCharacteristic, commandWithChecksum(
|
builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||||
@ -404,7 +334,7 @@ public class TeclastH30Support extends AbstractBTLEDeviceSupport {
|
|||||||
));
|
));
|
||||||
builder.queue(getQueue());
|
builder.queue(getQueue());
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
LOG.warn(e.getMessage());
|
logger.warn(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -466,7 +396,7 @@ public class TeclastH30Support extends AbstractBTLEDeviceSupport {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] commandWithChecksum(byte cmd, int argSlot1, int argSlot2)
|
protected byte[] commandWithChecksum(byte cmd, int argSlot1, int argSlot2)
|
||||||
{
|
{
|
||||||
ByteBuffer buf = ByteBuffer.allocate(10);
|
ByteBuffer buf = ByteBuffer.allocate(10);
|
||||||
buf.put(cmd);
|
buf.put(cmd);
|
||||||
@ -505,7 +435,7 @@ public class TeclastH30Support extends AbstractBTLEDeviceSupport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
LOG.warn(e.getMessage());
|
logger.warn(e.getMessage());
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
@ -0,0 +1,95 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.jyou;
|
||||||
|
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
||||||
|
|
||||||
|
public abstract class RealtimeSamplesSupport {
|
||||||
|
private final long delay;
|
||||||
|
private final long period;
|
||||||
|
|
||||||
|
protected int steps;
|
||||||
|
protected int heartrateBpm;
|
||||||
|
private int lastSteps;
|
||||||
|
// subclasses may add more
|
||||||
|
|
||||||
|
private Timer realtimeStorageTimer;
|
||||||
|
|
||||||
|
public RealtimeSamplesSupport(long delay, long period) {
|
||||||
|
this.delay = delay;
|
||||||
|
this.period = period;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void start() {
|
||||||
|
if (isRunning()) {
|
||||||
|
return; // already running
|
||||||
|
}
|
||||||
|
realtimeStorageTimer = new Timer("JYou Realtime Storage Timer");
|
||||||
|
realtimeStorageTimer.scheduleAtFixedRate(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
triggerCurrentSample();
|
||||||
|
}
|
||||||
|
}, delay, period);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void stop() {
|
||||||
|
if (realtimeStorageTimer != null) {
|
||||||
|
realtimeStorageTimer.cancel();
|
||||||
|
realtimeStorageTimer.purge();
|
||||||
|
realtimeStorageTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized boolean isRunning() {
|
||||||
|
return realtimeStorageTimer != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void setSteps(int stepsPerMinute) {
|
||||||
|
this.steps = stepsPerMinute;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of steps recorded since the last measurements. If no
|
||||||
|
* steps are available yet, ActivitySample.NOT_MEASURED is returned.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public synchronized int getSteps() {
|
||||||
|
if (steps == ActivitySample.NOT_MEASURED) {
|
||||||
|
return ActivitySample.NOT_MEASURED;
|
||||||
|
}
|
||||||
|
if (lastSteps == 0) {
|
||||||
|
return ActivitySample.NOT_MEASURED; // wait until we have a delta between two samples
|
||||||
|
}
|
||||||
|
int delta = steps - lastSteps;
|
||||||
|
if (delta < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeartrateBpm(int hrBpm) {
|
||||||
|
this.heartrateBpm = hrBpm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHeartrateBpm() {
|
||||||
|
return heartrateBpm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void triggerCurrentSample() {
|
||||||
|
doCurrentSample();
|
||||||
|
resetCurrentValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected synchronized void resetCurrentValues() {
|
||||||
|
if (steps >= lastSteps) {
|
||||||
|
lastSteps = steps;
|
||||||
|
}
|
||||||
|
steps = ActivitySample.NOT_MEASURED;
|
||||||
|
heartrateBpm = ActivitySample.NOT_MEASURED;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void doCurrentSample();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,121 @@
|
|||||||
|
/* Copyright (C) 2017-2019 Andreas Shimokawa, Carsten Pfeiffer, Sami Alaoui,
|
||||||
|
Sebastian Kranz
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.jyou.TeclastH30;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothGatt;
|
||||||
|
import android.bluetooth.BluetoothGattCharacteristic;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.jyou.JYouConstants;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.jyou.JYouSupport;
|
||||||
|
|
||||||
|
public class TeclastH30Support extends JYouSupport {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(TeclastH30Support.class);
|
||||||
|
|
||||||
|
public TeclastH30Support() {
|
||||||
|
super(LOG);
|
||||||
|
addSupportedService(JYouConstants.UUID_SERVICE_JYOU);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCharacteristicChanged(BluetoothGatt gatt,
|
||||||
|
BluetoothGattCharacteristic characteristic) {
|
||||||
|
if (super.onCharacteristicChanged(gatt, characteristic)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
UUID characteristicUUID = characteristic.getUuid();
|
||||||
|
byte[] data = characteristic.getValue();
|
||||||
|
if (data.length == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
switch (data[0]) {
|
||||||
|
case JYouConstants.RECEIVE_DEVICE_INFO:
|
||||||
|
int fwVerNum = data[4] & 0xFF;
|
||||||
|
versionCmd.fwVersion = (fwVerNum / 100) + "." + ((fwVerNum % 100) / 10) + "." + ((fwVerNum % 100) % 10);
|
||||||
|
handleGBDeviceEvent(versionCmd);
|
||||||
|
LOG.info("Firmware version is: " + versionCmd.fwVersion);
|
||||||
|
return true;
|
||||||
|
case JYouConstants.RECEIVE_BATTERY_LEVEL:
|
||||||
|
batteryCmd.level = data[8];
|
||||||
|
handleGBDeviceEvent(batteryCmd);
|
||||||
|
LOG.info("Battery level is: " + batteryCmd.level);
|
||||||
|
return true;
|
||||||
|
case JYouConstants.RECEIVE_STEPS_DATA:
|
||||||
|
int steps = ByteBuffer.wrap(data, 5, 4).getInt();
|
||||||
|
LOG.info("Number of walked steps: " + steps);
|
||||||
|
return true;
|
||||||
|
case JYouConstants.RECEIVE_HEARTRATE:
|
||||||
|
LOG.info("Current heart rate: " + data[8]);
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
LOG.info("Unhandled characteristic change: " + characteristicUUID + " code: " + String.format("0x%1x ...", data[0]));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void syncSettings(TransactionBuilder builder) {
|
||||||
|
syncDateAndTime(builder);
|
||||||
|
|
||||||
|
// TODO: unhardcode and separate stuff
|
||||||
|
builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||||
|
JYouConstants.CMD_SET_HEARTRATE_WARNING_VALUE, 0, 152
|
||||||
|
));
|
||||||
|
builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||||
|
JYouConstants.CMD_SET_TARGET_STEPS, 0, 10000
|
||||||
|
));
|
||||||
|
builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||||
|
JYouConstants.CMD_GET_STEP_COUNT, 0, 0
|
||||||
|
));
|
||||||
|
builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||||
|
JYouConstants.CMD_GET_SLEEP_TIME, 0, 0
|
||||||
|
));
|
||||||
|
builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||||
|
JYouConstants.CMD_SET_NOON_TIME, 12 * 60 * 60, 14 * 60 * 60 // 12:00 - 14:00
|
||||||
|
));
|
||||||
|
builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||||
|
JYouConstants.CMD_SET_SLEEP_TIME, 21 * 60 * 60, 8 * 60 * 60 // 21:00 - 08:00
|
||||||
|
));
|
||||||
|
builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||||
|
JYouConstants.CMD_SET_INACTIVITY_WARNING_TIME, 0, 0
|
||||||
|
));
|
||||||
|
|
||||||
|
// do not disturb and a couple more features
|
||||||
|
byte dndStartHour = 22;
|
||||||
|
byte dndStartMin = 0;
|
||||||
|
byte dndEndHour = 8;
|
||||||
|
byte dndEndMin = 0;
|
||||||
|
boolean dndToggle = false;
|
||||||
|
boolean vibrationToggle = true;
|
||||||
|
boolean wakeOnRaiseToggle = true;
|
||||||
|
builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||||
|
JYouConstants.CMD_SET_DND_SETTINGS,
|
||||||
|
(dndStartHour << 24) | (dndStartMin << 16) | (dndEndHour << 8) | dndEndMin,
|
||||||
|
((dndToggle ? 0 : 1) << 2) | ((vibrationToggle ? 1 : 0) << 1) | (wakeOnRaiseToggle ? 1 : 0)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,233 @@
|
|||||||
|
/* Copyright (C) 2017-2019 Andreas Shimokawa, Carsten Pfeiffer, Sami Alaoui,
|
||||||
|
Sebastian Kranz
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.jyou.y5;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothGatt;
|
||||||
|
import android.bluetooth.BluetoothGattCharacteristic;
|
||||||
|
import android.content.Intent;
|
||||||
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.jyou.JYouConstants;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.jyou.JYouSampleProvider;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.JYouActivitySample;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.entities.User;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.jyou.JYouSupport;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.jyou.RealtimeSamplesSupport;
|
||||||
|
|
||||||
|
public class Y5Support extends JYouSupport {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(Y5Support.class);
|
||||||
|
|
||||||
|
private RealtimeSamplesSupport realtimeSamplesSupport;
|
||||||
|
|
||||||
|
|
||||||
|
public Y5Support() {
|
||||||
|
super(LOG);
|
||||||
|
addSupportedService(JYouConstants.UUID_SERVICE_JYOU);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCharacteristicChanged(BluetoothGatt gatt,
|
||||||
|
BluetoothGattCharacteristic characteristic) {
|
||||||
|
if (super.onCharacteristicChanged(gatt, characteristic)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
UUID characteristicUUID = characteristic.getUuid();
|
||||||
|
byte[] data = characteristic.getValue();
|
||||||
|
if (data.length == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
switch (data[0]) {
|
||||||
|
case JYouConstants.RECEIVE_HISTORY_SLEEP_COUNT:
|
||||||
|
LOG.info("onCharacteristicChanged: " + data[0]);
|
||||||
|
return true;
|
||||||
|
case JYouConstants.RECEIVE_BLOOD_PRESSURE:
|
||||||
|
int heartRate = data[2];
|
||||||
|
int bloodPressureHigh = data[3];
|
||||||
|
int bloodPressureLow = data[4];
|
||||||
|
int bloodOxygen = data[5];
|
||||||
|
int Fatigue = data[6];
|
||||||
|
LOG.info("RECEIVE_BLOOD_PRESSURE: Heart rate: " + heartRate + " Pressure high: " + bloodPressureHigh+ " pressure low: " + bloodPressureLow);
|
||||||
|
return true;
|
||||||
|
case JYouConstants.RECEIVE_DEVICE_INFO:
|
||||||
|
int model = data[7];
|
||||||
|
int fwVerNum = data[4] & 0xFF;
|
||||||
|
versionCmd.fwVersion = (fwVerNum / 100) + "." + ((fwVerNum % 100) / 10) + "." + ((fwVerNum % 100) % 10);
|
||||||
|
handleGBDeviceEvent(versionCmd);
|
||||||
|
LOG.info("Firmware version is: " + versionCmd.fwVersion);
|
||||||
|
return true;
|
||||||
|
case JYouConstants.RECEIVE_BATTERY_LEVEL:
|
||||||
|
batteryCmd.level = data[8];
|
||||||
|
handleGBDeviceEvent(batteryCmd);
|
||||||
|
LOG.info("Battery level is: " + batteryCmd.level);
|
||||||
|
return true;
|
||||||
|
case JYouConstants.RECEIVE_STEPS_DATA:
|
||||||
|
int steps = ByteBuffer.wrap(data, 5, 4).getInt();
|
||||||
|
LOG.info("Number of walked steps: " + steps);
|
||||||
|
handleRealtimeSteps(steps);
|
||||||
|
return true;
|
||||||
|
case JYouConstants.RECEIVE_HEARTRATE:
|
||||||
|
handleHeartrate(data[8]);
|
||||||
|
return true;
|
||||||
|
case JYouConstants.RECEIVE_WATCH_MAC:
|
||||||
|
return true;
|
||||||
|
case JYouConstants.RECEIVE_GET_PHOTO:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
LOG.info("Unhandled characteristic change: " + characteristicUUID + " code: " + String.format("0x%1x ...", data[0]));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleRealtimeSteps(int value) {
|
||||||
|
//todo Call on connect the device
|
||||||
|
if (LOG.isDebugEnabled()) {
|
||||||
|
LOG.debug("realtime steps: " + value);
|
||||||
|
}
|
||||||
|
getRealtimeSamplesSupport().setSteps(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleHeartrate(int value) {
|
||||||
|
if (LOG.isDebugEnabled()) {
|
||||||
|
LOG.debug("heart rate: " + value);
|
||||||
|
}
|
||||||
|
RealtimeSamplesSupport realtimeSamplesSupport = getRealtimeSamplesSupport();
|
||||||
|
realtimeSamplesSupport.setHeartrateBpm(value);
|
||||||
|
if (!realtimeSamplesSupport.isRunning()) {
|
||||||
|
// single shot measurement, manually invoke storage and result publishing
|
||||||
|
realtimeSamplesSupport.triggerCurrentSample();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public JYouActivitySample createActivitySample(Device device, User user, int timestampInSeconds, SampleProvider provider) {
|
||||||
|
JYouActivitySample sample = new JYouActivitySample();
|
||||||
|
sample.setDevice(device);
|
||||||
|
sample.setUser(user);
|
||||||
|
sample.setTimestamp(timestampInSeconds);
|
||||||
|
sample.setProvider(provider);
|
||||||
|
return sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void enableRealtimeSamplesTimer(boolean enable) {
|
||||||
|
if (enable) {
|
||||||
|
getRealtimeSamplesSupport().start();
|
||||||
|
} else {
|
||||||
|
if (realtimeSamplesSupport != null) {
|
||||||
|
realtimeSamplesSupport.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private RealtimeSamplesSupport getRealtimeSamplesSupport() {
|
||||||
|
if (realtimeSamplesSupport == null) {
|
||||||
|
realtimeSamplesSupport = new RealtimeSamplesSupport(1000, 1000) {
|
||||||
|
@Override
|
||||||
|
public void doCurrentSample() {
|
||||||
|
|
||||||
|
try (DBHandler handler = GBApplication.acquireDB()) {
|
||||||
|
DaoSession session = handler.getDaoSession();
|
||||||
|
int ts = (int) (System.currentTimeMillis() / 1000);
|
||||||
|
JYouSampleProvider provider = new JYouSampleProvider(gbDevice, session);
|
||||||
|
JYouActivitySample sample = createActivitySample(DBHelper.getDevice(getDevice(), session), DBHelper.getUser(session), ts, provider);
|
||||||
|
sample.setHeartRate(getHeartrateBpm());
|
||||||
|
sample.setRawIntensity(ActivitySample.NOT_MEASURED);
|
||||||
|
sample.setRawKind(JYouSampleProvider.TYPE_ACTIVITY); // to make it visible in the charts TODO: add a MANUAL kind for that?
|
||||||
|
|
||||||
|
provider.addGBActivitySample(sample);
|
||||||
|
|
||||||
|
// set the steps only afterwards, since realtime steps are also recorded
|
||||||
|
// in the regular samples and we must not count them twice
|
||||||
|
// Note: we know that the DAO sample is never committed again, so we simply
|
||||||
|
// change the value here in memory.
|
||||||
|
sample.setSteps(getSteps());
|
||||||
|
if(steps > 1){
|
||||||
|
LOG.debug("Have steps: " + getSteps());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LOG.isDebugEnabled()) {
|
||||||
|
LOG.debug("realtime sample: " + sample);
|
||||||
|
}
|
||||||
|
|
||||||
|
Intent intent = new Intent(DeviceService.ACTION_REALTIME_SAMPLES)
|
||||||
|
.putExtra(DeviceService.EXTRA_REALTIME_SAMPLE, sample);
|
||||||
|
LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.warn("Unable to acquire db for saving realtime samples", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return realtimeSamplesSupport;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void syncSettings(TransactionBuilder builder) {
|
||||||
|
syncDateAndTime(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose() {
|
||||||
|
LOG.info("Dispose");
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onHeartRateTest() {
|
||||||
|
try {
|
||||||
|
TransactionBuilder builder = performInitialized("HeartRateTest");
|
||||||
|
builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||||
|
JYouConstants.CMD_SET_HEARTRATE_AUTO, 0, 0
|
||||||
|
|
||||||
|
));
|
||||||
|
performConnected(builder.getTransaction());
|
||||||
|
} catch(Exception e) {
|
||||||
|
LOG.warn(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnableRealtimeHeartRateMeasurement(boolean enable) {
|
||||||
|
try {
|
||||||
|
TransactionBuilder builder = performInitialized("RealTimeHeartMeasurement");
|
||||||
|
builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||||
|
JYouConstants.CMD_ACTION_HEARTRATE_SWITCH, 0, enable ? 1 : 0
|
||||||
|
));
|
||||||
|
performConnected(builder.getTransaction());
|
||||||
|
enableRealtimeSamplesTimer(enable);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.warn(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -7,12 +7,13 @@ import org.json.JSONException;
|
|||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil.FossilWatchAdapter;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil.FossilWatchAdapter;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil_hr.FossilHRWatchAdapter;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.json.JsonPutRequest;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.json.JsonPutRequest;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
|
|
||||||
public class ButtonConfigurationPutRequest extends JsonPutRequest {
|
public class ButtonConfigurationPutRequest extends JsonPutRequest {
|
||||||
public ButtonConfigurationPutRequest(String[] menuItems, FossilWatchAdapter adapter) {
|
public ButtonConfigurationPutRequest(String[] menuItems, FossilHRWatchAdapter adapter) {
|
||||||
super((short) 0x0500, createObject(menuItems), adapter);
|
super(createObject(menuItems), adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static JSONObject createObject(String[] menuItems) {
|
private static JSONObject createObject(String[] menuItems) {
|
||||||
|
@ -11,14 +11,14 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.utils.String
|
|||||||
|
|
||||||
public class AssetFilePutRequest extends FilePutRequest {
|
public class AssetFilePutRequest extends FilePutRequest {
|
||||||
public AssetFilePutRequest(AssetFile[] files, FossilWatchAdapter adapter) throws IOException {
|
public AssetFilePutRequest(AssetFile[] files, FossilWatchAdapter adapter) throws IOException {
|
||||||
super((short) 0x0701, prepareFileData(files), adapter);
|
super((short) 0x0700, prepareFileData(files), adapter);
|
||||||
}
|
}
|
||||||
public AssetFilePutRequest(AssetFile file, FossilWatchAdapter adapter) throws IOException {
|
public AssetFilePutRequest(AssetFile file, FossilWatchAdapter adapter) throws IOException {
|
||||||
super((short) 0x0701, prepareFileData(file), adapter);
|
super((short) 0x0700, prepareFileData(file), adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AssetFilePutRequest(AssetFile file, int subHandle, FossilWatchAdapter adapter) throws IOException {
|
public AssetFilePutRequest(AssetFile file, int subHandle, FossilWatchAdapter adapter) throws IOException {
|
||||||
super((short) (0x0701 | subHandle), prepareFileData(file), adapter);
|
super((short) (0x0700 | subHandle), prepareFileData(file), adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] prepareFileData(AssetFile[] files) throws IOException {
|
private static byte[] prepareFileData(AssetFile[] files) throws IOException {
|
||||||
|
@ -5,11 +5,12 @@ import org.json.JSONException;
|
|||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil.FossilWatchAdapter;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil.FossilWatchAdapter;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil_hr.FossilHRWatchAdapter;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.json.JsonPutRequest;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.json.JsonPutRequest;
|
||||||
|
|
||||||
public class ImagesSetRequest extends JsonPutRequest {
|
public class ImagesSetRequest extends JsonPutRequest {
|
||||||
public ImagesSetRequest(AssetImage[] images, FossilWatchAdapter adapter) {
|
public ImagesSetRequest(AssetImage[] images, FossilHRWatchAdapter adapter) {
|
||||||
super((short) 0x0503, prepareObject(images), adapter);
|
super(prepareObject(images), adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static JSONObject prepareObject(AssetImage[] images){
|
private static JSONObject prepareObject(AssetImage[] images){
|
||||||
|
@ -3,11 +3,12 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fo
|
|||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil.FossilWatchAdapter;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil.FossilWatchAdapter;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil_hr.FossilHRWatchAdapter;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.file.FilePutRequest;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.file.FilePutRequest;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.file.FilePutRawRequest;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.file.FilePutRawRequest;
|
||||||
|
|
||||||
public class JsonPutRequest extends FilePutRawRequest {
|
public class JsonPutRequest extends FilePutRawRequest {
|
||||||
public JsonPutRequest(short handle, JSONObject object, FossilWatchAdapter adapter) {
|
public JsonPutRequest(JSONObject object, FossilHRWatchAdapter adapter) {
|
||||||
super(handle, object.toString().getBytes(), adapter);
|
super((short)(0x0500 | adapter.getJsonIndex()), object.toString().getBytes(), adapter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,12 @@ import org.json.JSONException;
|
|||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil.FossilWatchAdapter;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil.FossilWatchAdapter;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil_hr.FossilHRWatchAdapter;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.json.JsonPutRequest;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.json.JsonPutRequest;
|
||||||
|
|
||||||
public class SetCommuteMenuMessage extends JsonPutRequest {
|
public class SetCommuteMenuMessage extends JsonPutRequest {
|
||||||
public SetCommuteMenuMessage(String message, boolean finished, FossilWatchAdapter adapter) {
|
public SetCommuteMenuMessage(String message, boolean finished, FossilHRWatchAdapter adapter) {
|
||||||
super((short) 0x0500, createObject(message, finished), adapter);
|
super(createObject(message, finished), adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static JSONObject createObject(String message, boolean finished) {
|
private static JSONObject createObject(String message, boolean finished) {
|
||||||
|
@ -5,12 +5,13 @@ import org.json.JSONException;
|
|||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil.FossilWatchAdapter;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil.FossilWatchAdapter;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil_hr.FossilHRWatchAdapter;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.file.FilePutRawRequest;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.file.FilePutRawRequest;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.json.JsonPutRequest;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.json.JsonPutRequest;
|
||||||
|
|
||||||
public class WidgetsPutRequest extends JsonPutRequest {
|
public class WidgetsPutRequest extends JsonPutRequest {
|
||||||
public WidgetsPutRequest(Widget[] widgets, FossilWatchAdapter adapter) {
|
public WidgetsPutRequest(Widget[] widgets, FossilHRWatchAdapter adapter) {
|
||||||
super((short) 0x0501, prepareFile(widgets), adapter);
|
super(prepareFile(widgets), adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static JSONObject prepareFile(Widget[] widgets){
|
private static JSONObject prepareFile(Widget[] widgets){
|
||||||
|
@ -67,6 +67,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.AlarmUtils;
|
import nodomain.freeyourgadget.gadgetbridge.util.AlarmUtils;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1682,7 +1683,9 @@ public class ZeTimeDeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setTimeFormate(TransactionBuilder builder) {
|
private void setTimeFormate(TransactionBuilder builder) {
|
||||||
String timeFormat = GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()).getString(DeviceSettingsPreferenceConst.PREF_TIMEFORMAT, "24h");
|
GBPrefs gbPrefs = new GBPrefs(new Prefs(GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress())));
|
||||||
|
|
||||||
|
String timeFormat = gbPrefs.getTimeFormat();
|
||||||
int type = 1;
|
int type = 1;
|
||||||
if ("am/pm".equals(timeFormat)) {
|
if ("am/pm".equals(timeFormat)) {
|
||||||
type = 2;
|
type = 2;
|
||||||
|
@ -60,8 +60,9 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huami.miband2.MiBand2HRXCoor
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.devices.huami.miband3.MiBand3Coordinator;
|
import nodomain.freeyourgadget.gadgetbridge.devices.huami.miband3.MiBand3Coordinator;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.huami.miband4.MiBand4Coordinator;
|
import nodomain.freeyourgadget.gadgetbridge.devices.huami.miband4.MiBand4Coordinator;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.id115.ID115Coordinator;
|
import nodomain.freeyourgadget.gadgetbridge.devices.id115.ID115Coordinator;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.jyou.TeclastH30.TeclastH30Coordinator;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.jyou.y5.Y5Coordinator;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.jyou.BFH16DeviceCoordinator;
|
import nodomain.freeyourgadget.gadgetbridge.devices.jyou.BFH16DeviceCoordinator;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.jyou.TeclastH30Coordinator;
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.liveview.LiveviewCoordinator;
|
import nodomain.freeyourgadget.gadgetbridge.devices.liveview.LiveviewCoordinator;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst;
|
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandCoordinator;
|
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandCoordinator;
|
||||||
@ -235,6 +236,7 @@ public class DeviceHelper {
|
|||||||
result.add(new Watch9DeviceCoordinator());
|
result.add(new Watch9DeviceCoordinator());
|
||||||
result.add(new Roidmi1Coordinator());
|
result.add(new Roidmi1Coordinator());
|
||||||
result.add(new Roidmi3Coordinator());
|
result.add(new Roidmi3Coordinator());
|
||||||
|
result.add(new Y5Coordinator());
|
||||||
result.add(new CasioGB6900DeviceCoordinator());
|
result.add(new CasioGB6900DeviceCoordinator());
|
||||||
result.add(new BFH16DeviceCoordinator());
|
result.add(new BFH16DeviceCoordinator());
|
||||||
result.add(new MijiaLywsd02Coordinator());
|
result.add(new MijiaLywsd02Coordinator());
|
||||||
|
@ -17,9 +17,14 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
package nodomain.freeyourgadget.gadgetbridge.util;
|
package nodomain.freeyourgadget.gadgetbridge.util;
|
||||||
|
|
||||||
|
import android.text.format.DateFormat;
|
||||||
|
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
|
||||||
|
|
||||||
public class GBPrefs {
|
public class GBPrefs {
|
||||||
public static final String PACKAGE_BLACKLIST = "package_blacklist";
|
public static final String PACKAGE_BLACKLIST = "package_blacklist";
|
||||||
public static final String PACKAGE_PEBBLEMSG_BLACKLIST = "package_pebblemsg_blacklist";
|
public static final String PACKAGE_PEBBLEMSG_BLACKLIST = "package_pebblemsg_blacklist";
|
||||||
@ -81,4 +86,17 @@ public class GBPrefs {
|
|||||||
public int getUserGender() {
|
public int getUserGender() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getTimeFormat() {
|
||||||
|
String timeFormat = mPrefs.getString(DeviceSettingsPreferenceConst.PREF_TIMEFORMAT, "auto");
|
||||||
|
if ("auto".equals(timeFormat)) {
|
||||||
|
if (DateFormat.is24HourFormat(GBApplication.getContext())) {
|
||||||
|
timeFormat = "24h";
|
||||||
|
} else {
|
||||||
|
timeFormat = "am/pm";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return timeFormat;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -365,11 +365,13 @@
|
|||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<string-array name="pref_timeformat_entries">
|
<string-array name="pref_timeformat_entries">
|
||||||
|
<item>@string/automatic</item>
|
||||||
<item>@string/timeformat_24h</item>
|
<item>@string/timeformat_24h</item>
|
||||||
<item>@string/timeformat_am_pm</item>
|
<item>@string/timeformat_am_pm</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<string-array name="pref_timeformat_values">
|
<string-array name="pref_timeformat_values">
|
||||||
|
<item>@string/p_timeformat_auto</item>
|
||||||
<item>@string/p_timeformat_24h</item>
|
<item>@string/p_timeformat_24h</item>
|
||||||
<item>@string/p_timeformat_am_pm</item>
|
<item>@string/p_timeformat_am_pm</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
@ -684,6 +684,7 @@
|
|||||||
<string name="devicetype_watch9">Watch 9</string>
|
<string name="devicetype_watch9">Watch 9</string>
|
||||||
<string name="devicetype_roidmi">Roidmi</string>
|
<string name="devicetype_roidmi">Roidmi</string>
|
||||||
<string name="devicetype_roidmi3">Roidmi 3</string>
|
<string name="devicetype_roidmi3">Roidmi 3</string>
|
||||||
|
<string name="devicetype_y5">Y5</string>
|
||||||
<string name="devicetype_casiogb6900">Casio GB-6900</string>
|
<string name="devicetype_casiogb6900">Casio GB-6900</string>
|
||||||
<string name="devicetype_miscale2">Mi Scale 2</string>
|
<string name="devicetype_miscale2">Mi Scale 2</string>
|
||||||
<string name="devicetype_bfh16">BFH-16</string>
|
<string name="devicetype_bfh16">BFH-16</string>
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
<item name="p_unit_metric" type="string">metric</item>
|
<item name="p_unit_metric" type="string">metric</item>
|
||||||
<item name="p_unit_imperial" type="string">imperial</item>
|
<item name="p_unit_imperial" type="string">imperial</item>
|
||||||
|
|
||||||
|
<item name="p_timeformat_auto" type="string">auto</item>
|
||||||
<item name="p_timeformat_24h" type="string">24h</item>
|
<item name="p_timeformat_24h" type="string">24h</item>
|
||||||
<item name="p_timeformat_am_pm" type="string">am/pm</item>
|
<item name="p_timeformat_am_pm" type="string">am/pm</item>
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:defaultValue="24h"
|
android:defaultValue="@string/p_timeformat_auto"
|
||||||
android:entries="@array/pref_timeformat_entries"
|
android:entries="@array/pref_timeformat_entries"
|
||||||
android:entryValues="@array/pref_timeformat_values"
|
android:entryValues="@array/pref_timeformat_values"
|
||||||
android:icon="@drawable/ic_access_time"
|
android:icon="@drawable/ic_access_time"
|
||||||
|
76
fastlane/collect_screenshots.sh
Executable file
@ -0,0 +1,76 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#This script needs bash for the read command
|
||||||
|
#Takes screenshots of Gadgetbridge for the fastlane.
|
||||||
|
#Live Activity screenshot not taken, as it needs more inputs.
|
||||||
|
|
||||||
|
VERSION="0421"
|
||||||
|
#Version sets clock in Android demo mode to version
|
||||||
|
#to indicate when screenshots have been taken
|
||||||
|
|
||||||
|
DIR="metadata/android/en-US/images/phoneScreenshots/"
|
||||||
|
#DIR="/tmp/"
|
||||||
|
|
||||||
|
#enable demo mode
|
||||||
|
adb shell settings put global sysui_demo_allowed 1
|
||||||
|
adb shell am broadcast -a com.android.systemui.demo -e command enter
|
||||||
|
adb shell am broadcast -a com.android.systemui.demo -e command clock -e hhmm $VERSION
|
||||||
|
adb shell am broadcast -a com.android.systemui.demo -e command notifications -e visible false
|
||||||
|
adb shell am broadcast -a com.android.systemui.demo -e command battery -e level 100
|
||||||
|
adb shell am broadcast -a com.android.systemui.demo -e command network -e wifi show -e level 4
|
||||||
|
adb shell am broadcast -a com.android.systemui.demo -e command network -e mobile show -e datatype none -e level 4
|
||||||
|
|
||||||
|
#launch Gadgetbridge
|
||||||
|
adb shell monkey -p nodomain.freeyourgadget.gadgetbridge -c android.intent.category.LAUNCHER 1
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
#Start taking screenshots:
|
||||||
|
|
||||||
|
adb shell screencap -p > $DIR"10-MainScreen.png"
|
||||||
|
|
||||||
|
adb shell input tap 455 355
|
||||||
|
sleep 0.5
|
||||||
|
adb shell screencap -p > $DIR"20-ActivityAndSleep.png"
|
||||||
|
|
||||||
|
adb shell input tap 240 210
|
||||||
|
read -p "slightly adjust label on chart and press Enter"
|
||||||
|
adb shell screencap -p > $DIR"30-Sleep.png"
|
||||||
|
|
||||||
|
adb shell input tap 420 210
|
||||||
|
read -p "slightly adjust label on chart and press Enter"
|
||||||
|
adb shell screencap -p > $DIR"40-SleepPerWeek.png"
|
||||||
|
|
||||||
|
#switch to month
|
||||||
|
adb shell input tap 670 100
|
||||||
|
sleep 0.5
|
||||||
|
adb shell input tap 670 1080
|
||||||
|
sleep 0.5
|
||||||
|
adb shell input keyevent 111
|
||||||
|
read -p "slightly adjust label on chart and press Enter"
|
||||||
|
|
||||||
|
adb shell screencap -p > $DIR"41-SleepPerMonth.png"
|
||||||
|
|
||||||
|
|
||||||
|
adb shell input tap 590 210
|
||||||
|
sleep 0.5
|
||||||
|
adb shell screencap -p > $DIR"51-StepsPerMonth.png"
|
||||||
|
|
||||||
|
#switch back to week
|
||||||
|
adb shell input tap 670 100
|
||||||
|
sleep 0.5
|
||||||
|
adb shell input tap 670 1080
|
||||||
|
sleep 0.5
|
||||||
|
adb shell input keyevent 111
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
adb shell screencap -p > $DIR"50-StepsPerWeek.png"
|
||||||
|
|
||||||
|
adb shell input tap 590 210
|
||||||
|
sleep 0.5
|
||||||
|
adb shell screencap -p > $DIR"60-SpeedZones.png"
|
||||||
|
|
||||||
|
#Go back to main screen
|
||||||
|
adb shell input keyevent 111
|
||||||
|
|
||||||
|
#disable demo mode
|
||||||
|
adb shell am broadcast -a com.android.systemui.demo -e command exit
|
||||||
|
adb shell settings put global sysui_demo_allowed 0
|
Before Width: | Height: | Size: 62 KiB |
After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 87 KiB |
After Width: | Height: | Size: 82 KiB |
Before Width: | Height: | Size: 88 KiB |
After Width: | Height: | Size: 73 KiB |
Before Width: | Height: | Size: 70 KiB |
After Width: | Height: | Size: 101 KiB |
After Width: | Height: | Size: 66 KiB |
Before Width: | Height: | Size: 54 KiB |
After Width: | Height: | Size: 78 KiB |
After Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 75 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 58 KiB |