mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-12-15 05:07:54 +01:00
noticed similarities to JYOU, copyed JYOU functions, adapted heartrate, blood presure and satiation values
Signed-off-by: Sophanimus
This commit is contained in:
parent
2c1f87c81b
commit
6faf9fdae8
@ -13,11 +13,51 @@ public final class BFH16Constants {
|
||||
|
||||
public static final UUID BFH16_MAIN_SERVICE = UUID.fromString(String.format(BASE_UUID, "33F4") );
|
||||
|
||||
|
||||
|
||||
//Known Services
|
||||
public static final UUID BFH16_SERVICE_1 = UUID.fromString("00001800-0000-1000-8000-00805f9b34fb");
|
||||
public static final UUID BFH16_SERVICE_2 = UUID.fromString("00001801-0000-1000-8000-00805f9b34fb"); //Attribute
|
||||
public static final UUID BFH16_SERVICE_3 = UUID.fromString("000056ff-0000-1000-8000-00805f9b34fb"); //Service
|
||||
public static final UUID BFH16_SERVICE_4 = UUID.fromString("0000fee7-0000-1000-8000-00805f9b34fb"); //Service
|
||||
|
||||
|
||||
|
||||
//I Think i discovered that this device (BFH16) uses communication similar to JYOU
|
||||
//Therefore i copied the following vars:
|
||||
public static final UUID UUID_CHARACTERISTIC_CONTROL = UUID.fromString("000033f3-0000-1000-8000-00805f9b34fb");
|
||||
public static final UUID UUID_CHARACTERISTIC_MEASURE = UUID.fromString("000033f4-0000-1000-8000-00805f9b34fb");
|
||||
public static final UUID UUID_SERVICE_JYOU = UUID.fromString("000056ff-0000-1000-8000-00805f9b34fb");
|
||||
|
||||
public static final byte CMD_SET_DATE_AND_TIME = 0x08;
|
||||
public static final byte CMD_SET_HEARTRATE_AUTO = 0x38;
|
||||
public static final byte CMD_SET_HEARTRATE_WARNING_VALUE = 0x01;
|
||||
public static final byte CMD_SET_TARGET_STEPS = 0x03;
|
||||
public static final byte CMD_SET_ALARM_1 = 0x09;
|
||||
public static final byte CMD_SET_ALARM_2 = 0x22;
|
||||
public static final byte CMD_SET_ALARM_3 = 0x23;
|
||||
public static final byte CMD_GET_STEP_COUNT = 0x1D;
|
||||
public static final byte CMD_GET_SLEEP_TIME = 0x32;
|
||||
public static final byte CMD_SET_NOON_TIME = 0x26;
|
||||
public static final byte CMD_SET_SLEEP_TIME = 0x27;
|
||||
public static final byte CMD_SET_DND_SETTINGS = 0x39;
|
||||
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_SHOW_NOTIFICATION = 0x2C;
|
||||
public static final byte CMD_ACTION_REBOOT_DEVICE = 0x0E;
|
||||
|
||||
public static final byte RECEIVE_BATTERY_LEVEL = (byte)0xF7;
|
||||
public static final byte RECEIVE_DEVICE_INFO = (byte)0xF6;
|
||||
public static final byte RECEIVE_STEPS_DATA = (byte)0xF9;
|
||||
public static final byte RECEIVE_HEARTRATE = (byte)0xE8;
|
||||
|
||||
public static final byte ICON_CALL = 0;
|
||||
public static final byte ICON_SMS = 1;
|
||||
public static final byte ICON_WECHAT = 2;
|
||||
public static final byte ICON_QQ = 3;
|
||||
public static final byte ICON_FACEBOOK = 4;
|
||||
public static final byte ICON_SKYPE = 5;
|
||||
public static final byte ICON_TWITTER = 6;
|
||||
public static final byte ICON_WHATSAPP = 7;
|
||||
public static final byte ICON_LINE = 8;
|
||||
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ public class BFH16DeviceCoordinator extends AbstractDeviceCoordinator
|
||||
|
||||
@Override
|
||||
public int getBondingStyle(GBDevice deviceCandidate){
|
||||
return BONDING_STYLE_NONE; //Might be wrong?
|
||||
return BONDING_STYLE_NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -77,187 +77,116 @@ public class BFH16DeviceCoordinator extends AbstractDeviceCoordinator
|
||||
return null;
|
||||
}
|
||||
|
||||
//Additional required functions
|
||||
//Additional required functions ______________________________________
|
||||
|
||||
/**
|
||||
* Hook for subclasses to perform device-specific deletion logic, e.g. db cleanup.
|
||||
* @param gbDevice the GBDevice
|
||||
* @param device the corresponding database Device
|
||||
* @param session the session to use
|
||||
* @throws GBException
|
||||
*/
|
||||
protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device device, @NonNull DaoSession session) throws GBException
|
||||
{
|
||||
@Override
|
||||
protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device device, @NonNull DaoSession session) throws GBException {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sample provider for the device being supported.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public SampleProvider<? extends ActivitySample> getSampleProvider(GBDevice device, DaoSession session)
|
||||
{
|
||||
return null; //FIXME
|
||||
@Override
|
||||
public SampleProvider<? extends ActivitySample> getSampleProvider(GBDevice device, DaoSession session) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an install handler for the given uri that can install the given
|
||||
* uri on the device being managed.
|
||||
*
|
||||
* @param uri
|
||||
* @param context
|
||||
* @return the install handler or null if that uri cannot be installed on the device
|
||||
*/
|
||||
public InstallHandler findInstallHandler(Uri uri, Context context)
|
||||
{
|
||||
return null; //FIXME
|
||||
@Override
|
||||
public InstallHandler findInstallHandler(Uri uri, Context context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Activity> getAppsManagementActivity()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
//SupportsXXX
|
||||
//SupportsXXX ________________________________________________________
|
||||
|
||||
/**
|
||||
* Returns true if activity data fetching is supported by the device
|
||||
* (with this coordinator).
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public int getAlarmSlotCount()
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsActivityDataFetching(){
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if activity tracking is supported by the device
|
||||
* (with this coordinator).
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsActivityTracking()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this device/coordinator supports taking screenshots.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean supportsScreenshots()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of alarms this device/coordinator supports
|
||||
* Shall return 0 also if it is not possible to set alarms via
|
||||
* protocol, but only on the smart device itself.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getAlarmSlotCount()
|
||||
{
|
||||
return 0; //FIXME
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this device/coordinator supports alarms with smart wakeup
|
||||
* @return
|
||||
*/
|
||||
public boolean supportsSmartWakeup(GBDevice device)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given device supports heart rate measurements.
|
||||
* @return
|
||||
*/
|
||||
public boolean supportsHeartRateMeasurement(GBDevice device)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this device/coordinator supports managing device apps.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsAppsManagement()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Activity class that will be used to manage device apps.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Class<? extends Activity> getAppsManagementActivity()
|
||||
{
|
||||
return null; //FIXME
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the device has some kind of calender we can sync to.
|
||||
* Also used for generated sunrise/sunset events
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsCalendarEvents()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the device supports getting a stream of live data.
|
||||
* This can be live HR, steps etc.
|
||||
*/
|
||||
public boolean supportsRealtimeData()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the device supports current weather and/or weather
|
||||
* forecast display.
|
||||
*/
|
||||
public boolean supportsWeather()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the device supports being found by vibrating,
|
||||
* making some sound or lighting up
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsFindDevice()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the device supports displaying music information
|
||||
* like artist, title, album, play state etc.
|
||||
*/
|
||||
public boolean supportsMusicInfo()
|
||||
@Override
|
||||
public boolean supportsHeartRateMeasurement(GBDevice device)
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the device has an led which supports custom colors
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsLedColor()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the device's led supports any RGB color,
|
||||
* or only preset colors
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsMusicInfo()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsRealtimeData()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsRgbLedColor()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsScreenshots() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsSmartWakeup(GBDevice device)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsWeather()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,14 +1,24 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.bfh16;
|
||||
|
||||
import android.bluetooth.BluetoothGatt;
|
||||
import android.bluetooth.BluetoothGattCharacteristic;
|
||||
import android.net.Uri;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.UUID;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.bfh16.BFH16Constants;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
|
||||
@ -18,14 +28,183 @@ import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.AlarmUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
||||
|
||||
public class BFH16DeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(BFH16DeviceSupport.class);
|
||||
|
||||
public BluetoothGattCharacteristic ctrlCharacteristic = null;
|
||||
public BluetoothGattCharacteristic measureCharacteristic = null;
|
||||
|
||||
private final GBDeviceEventVersionInfo versionCmd = new GBDeviceEventVersionInfo();
|
||||
private final GBDeviceEventBatteryInfo batteryCmd = new GBDeviceEventBatteryInfo();
|
||||
|
||||
public BFH16DeviceSupport() {
|
||||
super(LOG);
|
||||
addSupportedService(BFH16Constants.BFH16_MAIN_SERVICE);
|
||||
addSupportedService(BFH16Constants.UUID_SERVICE_JYOU);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TransactionBuilder initializeDevice(TransactionBuilder builder) {
|
||||
LOG.info("Initializing");
|
||||
|
||||
gbDevice.setState(GBDevice.State.INITIALIZING);
|
||||
gbDevice.sendDeviceUpdateIntent(getContext());
|
||||
|
||||
measureCharacteristic = getCharacteristic(BFH16Constants.UUID_CHARACTERISTIC_MEASURE);
|
||||
ctrlCharacteristic = getCharacteristic(BFH16Constants.UUID_CHARACTERISTIC_CONTROL);
|
||||
|
||||
builder.setGattCallback(this);
|
||||
builder.notify(measureCharacteristic, true);
|
||||
|
||||
syncSettings(builder);
|
||||
|
||||
gbDevice.setState(GBDevice.State.INITIALIZED);
|
||||
gbDevice.sendDeviceUpdateIntent(getContext());
|
||||
|
||||
LOG.info("Initialization Done");
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
@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 BFH16Constants.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 BFH16Constants.RECEIVE_BATTERY_LEVEL:
|
||||
batteryCmd.level = data[8];
|
||||
handleGBDeviceEvent(batteryCmd);
|
||||
LOG.info("Battery level is: " + batteryCmd.level);
|
||||
return true;
|
||||
case BFH16Constants.RECEIVE_STEPS_DATA:
|
||||
int steps = ByteBuffer.wrap(data, 5, 4).getInt();
|
||||
LOG.info("Number of walked steps: " + steps);
|
||||
return true;
|
||||
case BFH16Constants.RECEIVE_HEARTRATE:
|
||||
LOG.info("Current heart rate: " + data[1]);
|
||||
LOG.info("Current blood presure: " + data[3] + "/" + data[2]);
|
||||
LOG.info("Current satiation: " + data[4]);
|
||||
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();
|
||||
String strYear = String.valueOf(cal.get(Calendar.YEAR));
|
||||
byte year1 = (byte)Integer.parseInt(strYear.substring(0, 2));
|
||||
byte year2 = (byte)Integer.parseInt(strYear.substring(2, 4));
|
||||
byte month = (byte)cal.get(Calendar.MONTH);
|
||||
byte day = (byte)cal.get(Calendar.DAY_OF_MONTH);
|
||||
byte hour = (byte)cal.get(Calendar.HOUR_OF_DAY);
|
||||
byte minute = (byte)cal.get(Calendar.MINUTE);
|
||||
byte second = (byte)cal.get(Calendar.SECOND);
|
||||
byte weekDay = (byte)cal.get(Calendar.DAY_OF_WEEK);
|
||||
|
||||
builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||
BFH16Constants.CMD_SET_DATE_AND_TIME,
|
||||
(year1 << 24) | (year2 << 16) | (month << 8) | day,
|
||||
(hour << 24) | (minute << 16) | (second << 8) | weekDay
|
||||
));
|
||||
}
|
||||
|
||||
private void syncSettings(TransactionBuilder builder) {
|
||||
syncDateAndTime(builder);
|
||||
|
||||
// TODO: unhardcode and separate stuff
|
||||
builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||
BFH16Constants.CMD_SET_HEARTRATE_WARNING_VALUE, 0, 152
|
||||
));
|
||||
builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||
BFH16Constants.CMD_SET_TARGET_STEPS, 0, 10000
|
||||
));
|
||||
builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||
BFH16Constants.CMD_GET_STEP_COUNT, 0, 0
|
||||
));
|
||||
builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||
BFH16Constants.CMD_GET_SLEEP_TIME, 0, 0
|
||||
));
|
||||
builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||
BFH16Constants.CMD_SET_NOON_TIME, 12 * 60 * 60, 14 * 60 * 60 // 12:00 - 14:00
|
||||
));
|
||||
builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||
BFH16Constants.CMD_SET_SLEEP_TIME, 21 * 60 * 60, 8 * 60 * 60 // 21:00 - 08:00
|
||||
));
|
||||
builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||
BFH16Constants.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(
|
||||
BFH16Constants.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) {
|
||||
try {
|
||||
TransactionBuilder builder = performInitialized("ShowNotification");
|
||||
|
||||
byte[] titleBytes = stringToUTF8Bytes(title, 16);
|
||||
byte[] messageBytes = stringToUTF8Bytes(message, 80);
|
||||
|
||||
for (int i = 1; i <= 7; i++)
|
||||
{
|
||||
byte[] currentPacket = new byte[20];
|
||||
currentPacket[0] = BFH16Constants.CMD_ACTION_SHOW_NOTIFICATION;
|
||||
currentPacket[1] = 7;
|
||||
currentPacket[2] = (byte)i;
|
||||
switch(i) {
|
||||
case 1:
|
||||
currentPacket[4] = icon;
|
||||
break;
|
||||
case 2:
|
||||
if (titleBytes != null) {
|
||||
System.arraycopy(titleBytes, 0, currentPacket, 3, 6);
|
||||
System.arraycopy(titleBytes, 6, currentPacket, 10, 10);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (messageBytes != null) {
|
||||
System.arraycopy(messageBytes, 16 * (i - 3), currentPacket, 3, 6);
|
||||
System.arraycopy(messageBytes, 6 + 16 * (i - 3), currentPacket, 10, 10);
|
||||
}
|
||||
break;
|
||||
}
|
||||
builder.write(ctrlCharacteristic, currentPacket);
|
||||
}
|
||||
builder.queue(getQueue());
|
||||
} catch (IOException e) {
|
||||
LOG.warn(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -38,63 +217,24 @@ public class BFH16DeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
String notificationTitle = StringUtils.getFirstOf(notificationSpec.sender, notificationSpec.title);
|
||||
byte icon;
|
||||
switch (notificationSpec.type) {
|
||||
// case GENERIC_SMS:
|
||||
// icon = JYouConstants.ICON_SMS;
|
||||
// break;
|
||||
// case FACEBOOK:
|
||||
// case FACEBOOK_MESSENGER:
|
||||
// icon = JYouConstants.ICON_FACEBOOK;
|
||||
// break;
|
||||
// case TWITTER:
|
||||
// icon = JYouConstants.ICON_TWITTER;
|
||||
// break;
|
||||
// case WHATSAPP:
|
||||
// icon = JYouConstants.ICON_WHATSAPP;
|
||||
// break;
|
||||
// default:
|
||||
// icon = JYouConstants.ICON_LINE;
|
||||
// break;
|
||||
case GENERIC_SMS:
|
||||
icon = BFH16Constants.ICON_SMS;
|
||||
break;
|
||||
case FACEBOOK:
|
||||
case FACEBOOK_MESSENGER:
|
||||
icon = BFH16Constants.ICON_FACEBOOK;
|
||||
break;
|
||||
case TWITTER:
|
||||
icon = BFH16Constants.ICON_TWITTER;
|
||||
break;
|
||||
case WHATSAPP:
|
||||
icon = BFH16Constants.ICON_WHATSAPP;
|
||||
break;
|
||||
default:
|
||||
icon = BFH16Constants.ICON_LINE;
|
||||
break;
|
||||
}
|
||||
//showNotification(icon, notificationTitle, notificationSpec.body); //TODO FIXME
|
||||
}
|
||||
|
||||
private void showNotification(byte icon, String title, String message) {
|
||||
//TODO implement
|
||||
// try {
|
||||
// TransactionBuilder builder = performInitialized("ShowNotification");
|
||||
//
|
||||
// byte[] titleBytes = stringToUTF8Bytes(title, 16);
|
||||
// byte[] messageBytes = stringToUTF8Bytes(message, 80);
|
||||
//
|
||||
// for (int i = 1; i <= 7; i++)
|
||||
// {
|
||||
// byte[] currentPacket = new byte[20];
|
||||
// currentPacket[0] = JYouConstants.CMD_ACTION_SHOW_NOTIFICATION;
|
||||
// currentPacket[1] = 7;
|
||||
// currentPacket[2] = (byte)i;
|
||||
// switch(i) {
|
||||
// case 1:
|
||||
// currentPacket[4] = icon;
|
||||
// break;
|
||||
// case 2:
|
||||
// if (titleBytes != null) {
|
||||
// System.arraycopy(titleBytes, 0, currentPacket, 3, 6);
|
||||
// System.arraycopy(titleBytes, 6, currentPacket, 10, 10);
|
||||
// }
|
||||
// break;
|
||||
// default:
|
||||
// if (messageBytes != null) {
|
||||
// System.arraycopy(messageBytes, 16 * (i - 3), currentPacket, 3, 6);
|
||||
// System.arraycopy(messageBytes, 6 + 16 * (i - 3), currentPacket, 10, 10);
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
// builder.write(ctrlCharacteristic, currentPacket);
|
||||
// }
|
||||
// builder.queue(getQueue());
|
||||
// } catch (IOException e) {
|
||||
// LOG.warn(e.getMessage());
|
||||
// }
|
||||
showNotification(icon, notificationTitle, notificationSpec.body);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -103,58 +243,58 @@ public class BFH16DeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetTime() {
|
||||
// try {
|
||||
// TransactionBuilder builder = performInitialized("SetTime");
|
||||
// syncDateAndTime(builder);
|
||||
// builder.queue(getQueue());
|
||||
// } catch(IOException e) {
|
||||
// LOG.warn(e.getMessage());
|
||||
// }
|
||||
public void onSetAlarms(ArrayList<? extends Alarm> alarms) {
|
||||
try {
|
||||
TransactionBuilder builder = performInitialized("SetAlarms");
|
||||
|
||||
for (int i = 0; i < alarms.size(); i++)
|
||||
{
|
||||
byte cmd;
|
||||
switch (i) {
|
||||
case 0:
|
||||
cmd = BFH16Constants.CMD_SET_ALARM_1;
|
||||
break;
|
||||
case 1:
|
||||
cmd = BFH16Constants.CMD_SET_ALARM_2;
|
||||
break;
|
||||
case 2:
|
||||
cmd = BFH16Constants.CMD_SET_ALARM_3;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
Calendar cal = AlarmUtils.toCalendar(alarms.get(i));
|
||||
builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||
cmd,
|
||||
alarms.get(i).getEnabled() ? cal.get(Calendar.HOUR_OF_DAY) : -1,
|
||||
alarms.get(i).getEnabled() ? cal.get(Calendar.MINUTE) : -1
|
||||
));
|
||||
}
|
||||
builder.queue(getQueue());
|
||||
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) {
|
||||
LOG.warn(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetAlarms(ArrayList<? extends Alarm> alarms) {
|
||||
// try {
|
||||
// TransactionBuilder builder = performInitialized("SetAlarms");
|
||||
//
|
||||
// for (int i = 0; i < alarms.size(); i++)
|
||||
// {
|
||||
// byte cmd;
|
||||
// switch (i) {
|
||||
// case 0:
|
||||
// cmd = JYouConstants.CMD_SET_ALARM_1;
|
||||
// break;
|
||||
// case 1:
|
||||
// cmd = JYouConstants.CMD_SET_ALARM_2;
|
||||
// break;
|
||||
// case 2:
|
||||
// cmd = JYouConstants.CMD_SET_ALARM_3;
|
||||
// break;
|
||||
// default:
|
||||
// return;
|
||||
// }
|
||||
// Calendar cal = AlarmUtils.toCalendar(alarms.get(i));
|
||||
// builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||
// cmd,
|
||||
// alarms.get(i).getEnabled() ? cal.get(Calendar.HOUR_OF_DAY) : -1,
|
||||
// alarms.get(i).getEnabled() ? cal.get(Calendar.MINUTE) : -1
|
||||
// ));
|
||||
// }
|
||||
// builder.queue(getQueue());
|
||||
// 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) {
|
||||
// LOG.warn(e.getMessage());
|
||||
// }
|
||||
public void onSetTime() {
|
||||
try {
|
||||
TransactionBuilder builder = performInitialized("SetTime");
|
||||
syncDateAndTime(builder);
|
||||
builder.queue(getQueue());
|
||||
} catch(IOException e) {
|
||||
LOG.warn(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetCallState(CallSpec callSpec) {
|
||||
// switch (callSpec.command) {
|
||||
// case CallSpec.CALL_INCOMING:
|
||||
// showNotification(JYouConstants.ICON_CALL, callSpec.name, callSpec.number);
|
||||
// break;
|
||||
// }
|
||||
switch (callSpec.command) {
|
||||
case CallSpec.CALL_INCOMING:
|
||||
showNotification(BFH16Constants.ICON_CALL, callSpec.name, callSpec.number);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -174,7 +314,7 @@ public class BFH16DeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
|
||||
@Override
|
||||
public void onEnableRealtimeSteps(boolean enable) {
|
||||
//onEnableRealtimeHeartRateMeasurement(enable);
|
||||
onEnableRealtimeHeartRateMeasurement(enable);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -214,50 +354,50 @@ public class BFH16DeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
|
||||
@Override
|
||||
public void onReset(int flags) {
|
||||
// try {
|
||||
// TransactionBuilder builder = performInitialized("Reboot");
|
||||
// builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||
// JYouConstants.CMD_ACTION_REBOOT_DEVICE, 0, 0
|
||||
// ));
|
||||
// builder.queue(getQueue());
|
||||
// } catch(Exception e) {
|
||||
// LOG.warn(e.getMessage());
|
||||
// }
|
||||
try {
|
||||
TransactionBuilder builder = performInitialized("Reboot");
|
||||
builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||
BFH16Constants.CMD_ACTION_REBOOT_DEVICE, 0, 0
|
||||
));
|
||||
builder.queue(getQueue());
|
||||
} catch(Exception e) {
|
||||
LOG.warn(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHeartRateTest() {
|
||||
// try {
|
||||
// TransactionBuilder builder = performInitialized("HeartRateTest");
|
||||
// builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||
// JYouConstants.CMD_ACTION_HEARTRATE_SWITCH, 0, 1
|
||||
// ));
|
||||
// builder.queue(getQueue());
|
||||
// } catch(Exception e) {
|
||||
// LOG.warn(e.getMessage());
|
||||
// }
|
||||
try {
|
||||
TransactionBuilder builder = performInitialized("HeartRateTest");
|
||||
builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||
BFH16Constants.CMD_ACTION_HEARTRATE_SWITCH, 0, 1
|
||||
));
|
||||
builder.queue(getQueue());
|
||||
} catch(Exception e) {
|
||||
LOG.warn(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnableRealtimeHeartRateMeasurement(boolean enable) {
|
||||
// // TODO: test
|
||||
// try {
|
||||
// TransactionBuilder builder = performInitialized("RealTimeHeartMeasurement");
|
||||
// builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||
// JYouConstants.CMD_SET_HEARTRATE_AUTO, 0, enable ? 1 : 0
|
||||
// ));
|
||||
// builder.queue(getQueue());
|
||||
// } catch(Exception e) {
|
||||
// LOG.warn(e.getMessage());
|
||||
// }
|
||||
// TODO: test
|
||||
try {
|
||||
TransactionBuilder builder = performInitialized("RealTimeHeartMeasurement");
|
||||
builder.write(ctrlCharacteristic, commandWithChecksum(
|
||||
BFH16Constants.CMD_SET_HEARTRATE_AUTO, 0, enable ? 1 : 0
|
||||
));
|
||||
builder.queue(getQueue());
|
||||
} catch(Exception e) {
|
||||
LOG.warn(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFindDevice(boolean start) {
|
||||
// if (start) {
|
||||
// showNotification(JYouConstants.ICON_QQ, "Gadgetbridge", "Bzzt! Bzzt!");
|
||||
// GB.toast(getContext(), "As your device doesn't have sound, it will only vibrate 3 times consecutively", Toast.LENGTH_LONG, GB.INFO);
|
||||
// }
|
||||
if (start) {
|
||||
showNotification(BFH16Constants.ICON_QQ, "Gadgetbridge", "Bzzt! Bzzt!");
|
||||
GB.toast(getContext(), "As your device doesn't have sound, it will only vibrate 3 times consecutively", Toast.LENGTH_LONG, GB.INFO);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -310,4 +450,47 @@ public class BFH16DeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
|
||||
}
|
||||
|
||||
private byte[] commandWithChecksum(byte cmd, int argSlot1, int argSlot2)
|
||||
{
|
||||
ByteBuffer buf = ByteBuffer.allocate(10);
|
||||
buf.put(cmd);
|
||||
buf.putInt(argSlot1);
|
||||
buf.putInt(argSlot2);
|
||||
|
||||
byte[] bytesToWrite = buf.array();
|
||||
|
||||
byte checksum = 0;
|
||||
for (byte b : bytesToWrite) {
|
||||
checksum += b;
|
||||
}
|
||||
|
||||
bytesToWrite[9] = checksum;
|
||||
|
||||
return bytesToWrite;
|
||||
}
|
||||
|
||||
private byte[] stringToUTF8Bytes(String src, int byteCount) {
|
||||
try {
|
||||
if (src == null)
|
||||
return null;
|
||||
|
||||
for (int i = src.length(); i > 0; i--) {
|
||||
String sub = src.substring(0, i);
|
||||
byte[] subUTF8 = sub.getBytes("UTF-8");
|
||||
|
||||
if (subUTF8.length == byteCount) {
|
||||
return subUTF8;
|
||||
}
|
||||
|
||||
if (subUTF8.length < byteCount) {
|
||||
byte[] largerSubUTF8 = new byte[byteCount];
|
||||
System.arraycopy(subUTF8, 0, largerSubUTF8, 0, subUTF8.length);
|
||||
return largerSubUTF8;
|
||||
}
|
||||
}
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
LOG.warn(e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user