mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2025-02-17 12:56:48 +01:00
merged.
added makibes hr3 OnSharedPreferenceChangeListener. added makibes hr3 reverse find device (find phone). added makibes hr3 heart rate/steps/firmware version.
This commit is contained in:
parent
b7a660ae58
commit
8b7d853097
@ -45,7 +45,7 @@ public class GBDaoGenerator {
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Schema schema = new Schema(20, MAIN_PACKAGE + ".entities");
|
||||
Schema schema = new Schema(21, MAIN_PACKAGE + ".entities");
|
||||
|
||||
Entity userAttributes = addUserAttributes(schema);
|
||||
Entity user = addUserInfo(schema, userAttributes);
|
||||
@ -60,6 +60,7 @@ public class GBDaoGenerator {
|
||||
Entity tag = addTag(schema);
|
||||
Entity userDefinedActivityOverlay = addActivityDescription(schema, tag, user);
|
||||
|
||||
addMakibesHR3ActivitySample(schema, user, device);
|
||||
addMiBandActivitySample(schema, user, device);
|
||||
addPebbleHealthActivitySample(schema, user, device);
|
||||
addPebbleHealthActivityKindOverlay(schema, user, device);
|
||||
@ -186,6 +187,16 @@ public class GBDaoGenerator {
|
||||
return deviceAttributes;
|
||||
}
|
||||
|
||||
private static Entity addMakibesHR3ActivitySample(Schema schema, Entity user, Entity device) {
|
||||
Entity activitySample = addEntity(schema, "MakibesHR3ActivitySample");
|
||||
activitySample.implementsSerializable();
|
||||
addCommonActivitySampleProperties("AbstractActivitySample", activitySample, user, device);
|
||||
activitySample.addIntProperty(SAMPLE_STEPS).notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||
activitySample.addIntProperty(SAMPLE_RAW_KIND).notNull().codeBeforeGetterAndSetter(OVERRIDE);
|
||||
addHeartRateProperties(activitySample);
|
||||
return activitySample;
|
||||
}
|
||||
|
||||
private static Entity addMiBandActivitySample(Schema schema, Entity user, Entity device) {
|
||||
Entity activitySample = addEntity(schema, "MiBandActivitySample");
|
||||
activitySample.implementsSerializable();
|
||||
@ -363,7 +374,7 @@ public class GBDaoGenerator {
|
||||
alarm.addBooleanProperty("smartWakeup").notNull();
|
||||
alarm.addIntProperty("repetition").notNull().codeBeforeGetter(
|
||||
"public boolean isRepetitive() { return getRepetition() != ALARM_ONCE; } " +
|
||||
"public boolean getRepetition(int dow) { return (this.repetition & dow) > 0; }"
|
||||
"public boolean getRepetition(int dow) { return (this.repetition & dow) > 0; }"
|
||||
);
|
||||
alarm.addIntProperty("hour").notNull();
|
||||
alarm.addIntProperty("minute").notNull();
|
||||
|
@ -21,6 +21,7 @@
|
||||
<uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" /> <!-- Used for reverse find device -->
|
||||
|
||||
<uses-permission android:name="cyanogenmod.permission.ACCESS_WEATHER_MANAGER" />
|
||||
<uses-permission android:name="cyanogenmod.permission.READ_WEATHER" />
|
||||
|
@ -24,15 +24,7 @@ public final class MakibesHR3Constants {
|
||||
|
||||
public static final UUID UUID_SERVICE = UUID.fromString("6e400001-b5a3-f393-e0a9-e50e24dcca9e");
|
||||
public static final UUID UUID_CHARACTERISTIC_CONTROL = UUID.fromString("6e400002-b5a3-f393-e0a9-e50e24dcca9e");
|
||||
|
||||
// time
|
||||
// mode ab:00:04:ff:7c:80:** (00: 24h, 01: 12h)
|
||||
|
||||
// confirm write?
|
||||
// ab:00:09:ff:52:80:00:13:06:09:0f:0b
|
||||
|
||||
// disconnect?
|
||||
// ab:00:03:ff:ff:80
|
||||
public static final UUID UUID_CHARACTERISTIC_REPORT = UUID.fromString("6e400003-b5a3-f393-e0a9-e50e24dcca9e");
|
||||
|
||||
// Services and Characteristics
|
||||
// 00001801-0000-1000-8000-00805f9b34fb
|
||||
@ -44,8 +36,8 @@ public final class MakibesHR3Constants {
|
||||
// 00002a04-0000-1000-8000-00805f9b34fb
|
||||
// 00002aa6-0000-1000-8000-00805f9b34fb
|
||||
// 6e400001-b5a3-f393-e0a9-e50e24dcca9e // Nordic UART Service
|
||||
// 6e400002-b5a3-f393-e0a9-e50e24dcca9e // control
|
||||
// 6e400003-b5a3-f393-e0a9-e50e24dcca9e
|
||||
// 6e400002-b5a3-f393-e0a9-e50e24dcca9e // control (RX)
|
||||
// 6e400003-b5a3-f393-e0a9-e50e24dcca9e // report
|
||||
// 0000fee7-0000-1000-8000-00805f9b34fb
|
||||
// 0000fec9-0000-1000-8000-00805f9b34fb
|
||||
// 0000fea1-0000-1000-8000-00805f9b34fb
|
||||
@ -55,10 +47,8 @@ public final class MakibesHR3Constants {
|
||||
// ab 00 [argument_count] ff [command] 80 [arguments]
|
||||
// where [argument_count] is [arguments].length + 3
|
||||
|
||||
// refresh sends
|
||||
// 51
|
||||
// 52
|
||||
// 93 (CMD_SET_DATE_TIME)
|
||||
// Report structure is the same but 80 might by different
|
||||
|
||||
|
||||
public static final byte[] DATA_TEMPLATE = {
|
||||
(byte) 0xab,
|
||||
@ -75,36 +65,78 @@ public final class MakibesHR3Constants {
|
||||
public static final int DATA_ARGUMENTS_INDEX = 6;
|
||||
|
||||
|
||||
// This is also used with different parameters.
|
||||
// steps take up more bytes. I don't know which ones yet.
|
||||
// Only sent after we send CMD_51
|
||||
// 00 (maybe also used for steps)
|
||||
// [steps hi]
|
||||
// [steps lo]
|
||||
// 00
|
||||
// 00
|
||||
// 01 (also was 0b. Maybe minutes of activity.)
|
||||
// 00
|
||||
// 00
|
||||
// 00
|
||||
// 00
|
||||
// 00
|
||||
public static final byte RPRT_FITNESS = (byte) 0x51;
|
||||
|
||||
|
||||
// enable (00/01)
|
||||
public static final byte RPRT_REVERSE_FIND_DEVICE = (byte) 0x7d;
|
||||
|
||||
|
||||
// heart rate
|
||||
public static final byte RPRT_HEARTRATE = (byte) 0x84;
|
||||
|
||||
|
||||
// 2 arguments.
|
||||
public static final byte RPRT_91 = (byte) 0x91;
|
||||
|
||||
// firmware_major
|
||||
// firmware_minor
|
||||
// 37
|
||||
// 00
|
||||
// 00
|
||||
// 00
|
||||
// 00
|
||||
// 00
|
||||
// 00
|
||||
// 20
|
||||
// 0e
|
||||
public static final byte RPRT_SOFTWARE = (byte) 0x92;
|
||||
|
||||
// 00
|
||||
public static final byte CMD_FACTORY_RESET = (byte) 0x23;
|
||||
|
||||
|
||||
// 00
|
||||
// year (+2000)
|
||||
// month
|
||||
// day
|
||||
// 0b
|
||||
// 00
|
||||
// month (not current! but close)
|
||||
// day (not current! but close)
|
||||
// 0b (A)
|
||||
// 00 (B)
|
||||
// year (+2000)
|
||||
// month
|
||||
// day
|
||||
// 0b
|
||||
// 19
|
||||
public static final byte CMD_UNKNOWN_51 = (byte) 0x51;
|
||||
// month (not current! but close)
|
||||
// day (not current! but close)
|
||||
// 0b (this is >= (A))
|
||||
// 19 (this is >= (B))
|
||||
public static final byte CMD_REQUEST_FITNESS = (byte) 0x51;
|
||||
|
||||
// this is the last command sent on sync
|
||||
// 00
|
||||
// year (+2000)
|
||||
// month
|
||||
// month (not current!)
|
||||
// 14 this isn't the current day
|
||||
// hour (current)
|
||||
// minute (current)
|
||||
public static final byte CMD_UNKNOWN_52 = (byte) 0x52;
|
||||
public static final byte CMD_52 = (byte) 0x52;
|
||||
|
||||
|
||||
public static final byte CMD_FIND_DEVICE = (byte) 0x71;
|
||||
|
||||
|
||||
// WearFit writes uses other sources as well. They don't do anything though.
|
||||
public static final byte ARG_SEND_NOTIFICATION_SOURCE_CALL = (byte) 0x01;
|
||||
public static final byte ARG_SEND_NOTIFICATION_SOURCE_STOP_CALL = (byte) 0x02;
|
||||
public static final byte ARG_SEND_NOTIFICATION_SOURCE_MESSAGE = (byte) 0x03;
|
||||
@ -118,7 +150,7 @@ public final class MakibesHR3Constants {
|
||||
public static final byte ARG_SEND_NOTIFICATION_SOURCE_WEIBO = (byte) 0x13;
|
||||
public static final byte ARG_SEND_NOTIFICATION_SOURCE_KAKOTALK = (byte) 0x14;
|
||||
// ARG_SET_NOTIFICATION_SOURCE_*
|
||||
// 02
|
||||
// 02 (This is 00 and 01 during connection. I don't know what it does. Maybe clears notifications?)
|
||||
// ASCII
|
||||
public static final byte CMD_SEND_NOTIFICATION = (byte) 0x72;
|
||||
|
||||
@ -177,6 +209,10 @@ public final class MakibesHR3Constants {
|
||||
public static final byte CMD_SET_HEADS_UP_SCREEN = (byte) 0x77;
|
||||
|
||||
|
||||
// Looks like enable/disable.
|
||||
public static final byte CMD_78 = (byte) 0x78;
|
||||
|
||||
|
||||
// The watch enters photograph mode, but doesn't appear to send a trigger signal.
|
||||
// enable (00/01)
|
||||
public static final byte CMD_SET_PHOTOGRAPH_MODE = (byte) 0x79;
|
||||
@ -188,14 +224,24 @@ public final class MakibesHR3Constants {
|
||||
|
||||
// 7b has 1 argument. Looks like enable/disable.
|
||||
|
||||
// 7e has 14 arguments.
|
||||
|
||||
public static final byte ARG_SET_TIMEMODE_24H = 0x00;
|
||||
public static final byte ARG_SET_TIMEMODE_12H = 0x01;
|
||||
// ARG_SET_TIMEMODE_*
|
||||
public static final byte CMD_SET_TIMEMODE = (byte) 0x7c;
|
||||
|
||||
|
||||
// 5 arguments.
|
||||
public static final byte CMD_7f = (byte) 0x7f;
|
||||
|
||||
|
||||
// enable (00/01)
|
||||
public static final byte CMD_SET_REAL_TIME_HEART_RATE = (byte) 0x84;
|
||||
|
||||
|
||||
// looks like enable/disable.
|
||||
public static final byte CMD_85 = (byte) 0x85;
|
||||
|
||||
|
||||
// 00
|
||||
// year hi
|
||||
// year lo
|
||||
@ -207,6 +253,14 @@ public final class MakibesHR3Constants {
|
||||
public static final byte CMD_SET_DATE_TIME = (byte) 0x93;
|
||||
|
||||
|
||||
// looks like enable/disable.
|
||||
public static final byte CMD_96 = (byte) 0x96;
|
||||
|
||||
|
||||
// looks like enable/disable.
|
||||
public static final byte CMD_e5 = (byte) 0xe5;
|
||||
|
||||
|
||||
// If this is sent after {@link CMD_FACTORY_RESET}, it's a shutdown, not a reboot.
|
||||
// Rebooting resets the watch face and wallpaper.
|
||||
public static final byte CMD_REBOOT = (byte) 0xff;
|
||||
|
@ -16,10 +16,18 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.makibeshr3;
|
||||
|
||||
/*
|
||||
* @author Alejandro Ladera Chamorro <11555126+tiparega@users.noreply.github.com>
|
||||
*/
|
||||
|
||||
|
||||
import android.app.Activity;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothGattCharacteristic;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
@ -48,20 +56,24 @@ public class MakibesHR3Coordinator extends AbstractDeviceCoordinator {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MakibesHR3Coordinator.class);
|
||||
|
||||
public static byte getTimeMode(String deviceAddress) {
|
||||
SharedPreferences sharedPrefs = GBApplication.getDeviceSpecificSharedPrefs(deviceAddress);
|
||||
|
||||
public static byte getTimeMode(SharedPreferences sharedPrefs) {
|
||||
String tmode = sharedPrefs.getString(DeviceSettingsPreferenceConst.PREF_TIMEFORMAT, getContext().getString(R.string.p_timeformat_24h));
|
||||
|
||||
LOG.debug("tmode is " + tmode);
|
||||
|
||||
if (getContext().getString(R.string.p_timeformat_24h).equals(tmode)) {
|
||||
if (tmode.equals(getContext().getString(R.string.p_timeformat_24h))) {
|
||||
return MakibesHR3Constants.ARG_SET_TIMEMODE_24H;
|
||||
} else {
|
||||
return MakibesHR3Constants.ARG_SET_TIMEMODE_12H;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte getTimeMode(String deviceAddress) {
|
||||
SharedPreferences sharedPrefs = GBApplication.getDeviceSpecificSharedPrefs(deviceAddress);
|
||||
|
||||
return getTimeMode(sharedPrefs);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public DeviceType getSupportedType(GBDeviceCandidate candidate) {
|
||||
@ -92,7 +104,7 @@ public class MakibesHR3Coordinator extends AbstractDeviceCoordinator {
|
||||
|
||||
@Override
|
||||
public boolean supportsRealtimeData() {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -123,12 +135,12 @@ public class MakibesHR3Coordinator extends AbstractDeviceCoordinator {
|
||||
|
||||
@Override
|
||||
public boolean supportsActivityTracking() {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SampleProvider<? extends ActivitySample> getSampleProvider(GBDevice device, DaoSession session) {
|
||||
return null;
|
||||
return new MakibesHR3SampleProvider(device, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,84 @@
|
||||
/* Copyright (C) 2018-2019 Daniele Gobbetti, 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.devices.makibeshr3;
|
||||
|
||||
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.MakibesHR3ActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.MakibesHR3ActivitySampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
|
||||
public class MakibesHR3SampleProvider extends AbstractSampleProvider<MakibesHR3ActivitySample> {
|
||||
|
||||
private GBDevice mDevice;
|
||||
private DaoSession mSession;
|
||||
|
||||
public MakibesHR3SampleProvider(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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MakibesHR3ActivitySample createActivitySample() {
|
||||
return new MakibesHR3ActivitySample();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractDao<MakibesHR3ActivitySample, ?> getSampleDao() {
|
||||
return getSession().getMakibesHR3ActivitySampleDao();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected Property getRawKindSampleProperty() {
|
||||
return MakibesHR3ActivitySampleDao.Properties.RawKind;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Property getTimestampSampleProperty() {
|
||||
return MakibesHR3ActivitySampleDao.Properties.Timestamp;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Property getDeviceIdentifierSampleProperty() {
|
||||
return MakibesHR3ActivitySampleDao.Properties.DeviceId;
|
||||
}
|
||||
}
|
@ -1,7 +1,26 @@
|
||||
// TODO: WearFit resets today's step count when it's used after GB.
|
||||
|
||||
// TODO: Battery level
|
||||
|
||||
// TODO: ALARM REMINDER REPETITION
|
||||
|
||||
// TODO: It'd be cool if we could change the language. There's no official way to do so, but the
|
||||
// TODO: watch is sold as chinese/english.
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.makibeshr3;
|
||||
|
||||
import android.bluetooth.BluetoothGatt;
|
||||
import android.bluetooth.BluetoothGattCharacteristic;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.VibrationEffect;
|
||||
import android.os.Vibrator;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -10,13 +29,23 @@ import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.UUID;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.makibeshr3.MakibesHR3Constants;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.makibeshr3.MakibesHR3Coordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.makibeshr3.MakibesHR3SampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.MakibesHR3ActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.User;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
@ -24,12 +53,20 @@ import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
|
||||
public class MakibesHR3DeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_TIMEFORMAT;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.makibeshr3.MakibesHR3Constants.RPRT_SOFTWARE;
|
||||
|
||||
public class MakibesHR3DeviceSupport extends AbstractBTLEDeviceSupport implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MakibesHR3DeviceSupport.class);
|
||||
|
||||
private BluetoothGattCharacteristic ctrlCharacteristic = null;
|
||||
private Vibrator mVibrator;
|
||||
|
||||
public BluetoothGattCharacteristic ctrlCharacteristic = null;
|
||||
public BluetoothGattCharacteristic rprtCharacteristic = null;
|
||||
|
||||
|
||||
public MakibesHR3DeviceSupport() {
|
||||
super(LOG);
|
||||
@ -42,6 +79,17 @@ public class MakibesHR3DeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
return false;
|
||||
}
|
||||
|
||||
public MakibesHR3ActivitySample createActivitySample(Device device, User user, int timestampInSeconds, SampleProvider provider) {
|
||||
MakibesHR3ActivitySample sample = new MakibesHR3ActivitySample();
|
||||
sample.setDevice(device);
|
||||
sample.setUser(user);
|
||||
sample.setTimestamp(timestampInSeconds);
|
||||
sample.setProvider(provider);
|
||||
|
||||
return sample;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onNotification(NotificationSpec notificationSpec) {
|
||||
TransactionBuilder transactionBuilder = this.createTransactionBuilder("onnotificaiton");
|
||||
@ -233,7 +281,34 @@ public class MakibesHR3DeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
|
||||
@Override
|
||||
public void onEnableRealtimeHeartRateMeasurement(boolean enable) {
|
||||
TransactionBuilder transactionBuilder = this.createTransactionBuilder("finddevice");
|
||||
|
||||
this.setEnableRealTimeHeartRate(transactionBuilder, enable);
|
||||
|
||||
try {
|
||||
this.performConnected(transactionBuilder.getTransaction());
|
||||
} catch (Exception e) {
|
||||
LOG.debug("ERROR");
|
||||
}
|
||||
}
|
||||
|
||||
private void onReverseFindDevice(boolean start) {
|
||||
final long[] PATTERN = new long[]{
|
||||
100, 100,
|
||||
100, 100,
|
||||
100, 100,
|
||||
500
|
||||
};
|
||||
|
||||
if (start) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
this.mVibrator.vibrate(VibrationEffect.createWaveform(PATTERN, 0));
|
||||
} else {
|
||||
this.mVibrator.vibrate(PATTERN, 0);
|
||||
}
|
||||
} else {
|
||||
this.mVibrator.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -304,12 +379,8 @@ public class MakibesHR3DeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
}
|
||||
|
||||
private MakibesHR3DeviceSupport sendUserInfo(TransactionBuilder builder) {
|
||||
// builder.write(ctrlCharacteristic, MakibesHR3Constants.CMD_SET_PREF_START);
|
||||
// builder.write(ctrlCharacteristic, MakibesHR3Constants.CMD_SET_PREF_START1);
|
||||
|
||||
syncPreferences(builder);
|
||||
|
||||
// builder.write(ctrlCharacteristic, new byte[]{MakibesHR3Constants.CMD_SET_CONF_END});
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -334,30 +405,158 @@ public class MakibesHR3DeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
return this;
|
||||
}
|
||||
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
LOG.debug(key + " changed");
|
||||
TransactionBuilder transactionBuilder = this.createTransactionBuilder("onSharedPreferenceChanged");
|
||||
|
||||
if (key.equals(PREF_TIMEFORMAT)) {
|
||||
this.setTimeMode(transactionBuilder);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.performConnected(transactionBuilder.getTransaction());
|
||||
} catch (Exception ex) {
|
||||
LOG.warn(ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TransactionBuilder initializeDevice(TransactionBuilder builder) {
|
||||
gbDevice.setState(GBDevice.State.INITIALIZING);
|
||||
gbDevice.sendDeviceUpdateIntent(getContext());
|
||||
|
||||
this.ctrlCharacteristic = getCharacteristic(MakibesHR3Constants.UUID_CHARACTERISTIC_CONTROL);
|
||||
this.rprtCharacteristic = getCharacteristic(MakibesHR3Constants.UUID_CHARACTERISTIC_REPORT);
|
||||
|
||||
this.mVibrator = (Vibrator) this.getContext().getSystemService(Context.VIBRATOR_SERVICE);
|
||||
|
||||
builder.notify(this.rprtCharacteristic, true);
|
||||
builder.setGattCallback(this);
|
||||
|
||||
|
||||
// Allow modifications
|
||||
builder.write(this.ctrlCharacteristic, new byte[]{0x01, 0x00});
|
||||
|
||||
// Initialize device
|
||||
sendUserInfo(builder); //Sync preferences
|
||||
|
||||
this.requestFitness(builder, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0);
|
||||
|
||||
gbDevice.setState(GBDevice.State.INITIALIZED);
|
||||
gbDevice.sendDeviceUpdateIntent(getContext());
|
||||
|
||||
getDevice().setFirmwareVersion("N/A");
|
||||
getDevice().setFirmwareVersion2("N/A");
|
||||
|
||||
SharedPreferences preferences = GBApplication.getDeviceSpecificSharedPrefs(this.getDevice().getAddress());
|
||||
|
||||
// TODO: Why doesn't this work?
|
||||
preferences.registerOnSharedPreferenceChangeListener(this);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
private void broadcastActivity(Integer heartRate, Integer steps) {
|
||||
try (DBHandler dbHandler = GBApplication.acquireDB()) {
|
||||
|
||||
User user = DBHelper.getUser(dbHandler.getDaoSession());
|
||||
Device device = DBHelper.getDevice(this.getDevice(), dbHandler.getDaoSession());
|
||||
|
||||
MakibesHR3SampleProvider provider = new MakibesHR3SampleProvider(this.getDevice(), dbHandler.getDaoSession());
|
||||
|
||||
int timeStamp = (int) (System.currentTimeMillis() / 1000);
|
||||
|
||||
MakibesHR3ActivitySample sample = this.createActivitySample(device, user, timeStamp, provider);
|
||||
|
||||
if (heartRate != null) {
|
||||
sample.setHeartRate(heartRate);
|
||||
}
|
||||
|
||||
if (steps != null) {
|
||||
sample.setSteps(steps);
|
||||
}
|
||||
|
||||
sample.setRawKind(-1);
|
||||
|
||||
provider.addGBActivitySample(sample);
|
||||
|
||||
Intent intent = new Intent(DeviceService.ACTION_REALTIME_SAMPLES)
|
||||
.putExtra(DeviceService.EXTRA_REALTIME_SAMPLE, sample)
|
||||
.putExtra(DeviceService.EXTRA_TIMESTAMP, timeStamp);
|
||||
LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
|
||||
|
||||
} catch (Exception ex) {
|
||||
GB.toast(getContext(), "Error saving steps data: " + ex.getLocalizedMessage(), Toast.LENGTH_LONG, GB.ERROR);
|
||||
GB.updateTransferNotification(null, "Data transfer failed", false, 0, getContext());
|
||||
}
|
||||
}
|
||||
|
||||
private void onReceiveFitness(int steps) {
|
||||
LOG.info("steps: " + steps);
|
||||
|
||||
this.broadcastActivity(null, steps);
|
||||
}
|
||||
|
||||
private void onReceiveHeartRate(int heartRate) {
|
||||
LOG.info("heart rate: " + heartRate);
|
||||
|
||||
this.broadcastActivity(heartRate, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCharacteristicChanged(BluetoothGatt gatt,
|
||||
BluetoothGattCharacteristic characteristic) {
|
||||
if (super.onCharacteristicChanged(gatt, characteristic)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
byte[] data = characteristic.getValue();
|
||||
if (data.length < 6)
|
||||
return true;
|
||||
|
||||
UUID characteristicUuid = characteristic.getUuid();
|
||||
|
||||
if (characteristicUuid.equals(rprtCharacteristic.getUuid())) {
|
||||
byte[] value = characteristic.getValue();
|
||||
byte[] arguments = new byte[value.length - 6];
|
||||
|
||||
for (int i = 0; i < arguments.length; ++i) {
|
||||
arguments[i] = value[i + 6];
|
||||
}
|
||||
|
||||
byte report = value[4];
|
||||
|
||||
LOG.debug("report: " + Integer.toHexString((int) report));
|
||||
|
||||
switch (report) {
|
||||
case MakibesHR3Constants.RPRT_FITNESS:
|
||||
if (value.length == 17) {
|
||||
this.onReceiveFitness(
|
||||
(int) arguments[1] * 0xff + arguments[2]
|
||||
);
|
||||
}
|
||||
break;
|
||||
case MakibesHR3Constants.RPRT_REVERSE_FIND_DEVICE:
|
||||
this.onReverseFindDevice(arguments[0] == 0x01);
|
||||
break;
|
||||
case MakibesHR3Constants.RPRT_HEARTRATE:
|
||||
if (value.length == 7) {
|
||||
this.onReceiveHeartRate((int) arguments[0]);
|
||||
}
|
||||
break;
|
||||
case RPRT_SOFTWARE:
|
||||
if (arguments.length == 11) {
|
||||
this.getDevice().setFirmwareVersion(((int) arguments[0]) + "." + ((int) arguments[1]));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param command
|
||||
* @param data
|
||||
@ -427,6 +626,31 @@ public class MakibesHR3DeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
return this.reboot(transaction);
|
||||
}
|
||||
|
||||
private MakibesHR3DeviceSupport requestFitness(TransactionBuilder transaction,
|
||||
int yearStart, int monthStart, int dayStart,
|
||||
int a4, int a5,
|
||||
int yearEnd, int monthEnd, int dayEnd,
|
||||
int a9, int a10) {
|
||||
|
||||
byte[] data = this.craftData(MakibesHR3Constants.CMD_REQUEST_FITNESS,
|
||||
new byte[]{
|
||||
(byte) (yearStart - 2000),
|
||||
(byte) monthStart,
|
||||
(byte) dayStart,
|
||||
(byte) a4,
|
||||
(byte) a5,
|
||||
(byte) (yearEnd - 2000),
|
||||
(byte) monthEnd,
|
||||
(byte) dayEnd,
|
||||
(byte) a9,
|
||||
(byte) a10
|
||||
});
|
||||
|
||||
transaction.write(this.ctrlCharacteristic, data);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private MakibesHR3DeviceSupport findDevice(TransactionBuilder transaction) {
|
||||
transaction.write(this.ctrlCharacteristic, this.craftData(MakibesHR3Constants.CMD_FIND_DEVICE));
|
||||
|
||||
@ -475,6 +699,14 @@ public class MakibesHR3DeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
return this;
|
||||
}
|
||||
|
||||
private MakibesHR3DeviceSupport setEnableRealTimeHeartRate(TransactionBuilder transaction, boolean enable) {
|
||||
byte[] data = this.craftData(MakibesHR3Constants.CMD_SET_REAL_TIME_HEART_RATE, new byte[]{(byte) (enable ? 0x01 : 0x00)});
|
||||
|
||||
transaction.write(this.ctrlCharacteristic, data);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private MakibesHR3DeviceSupport setDateTime(TransactionBuilder transaction,
|
||||
int year,
|
||||
int month,
|
||||
|
Loading…
x
Reference in New Issue
Block a user