1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-12-29 12:05:53 +01:00

added abstraction layer

This commit is contained in:
Daniel Dakhno 2019-10-24 19:44:35 +02:00
parent 93726f9e37
commit 187600b076
43 changed files with 622 additions and 444 deletions

View File

@ -4,10 +4,10 @@ import android.util.Log;
import java.io.Serializable;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.PlayNotificationRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.PlayNotificationRequest;
public class PackageConfig implements Serializable {
private short min, hour;
private short min, hour, activity = -1;
private String packageName, appName;
private PlayNotificationRequest.VibrationType vibration;
private boolean respectSilentMode;
@ -22,6 +22,13 @@ public class PackageConfig implements Serializable {
this.vibration = vibration;
}
public PackageConfig(short min, short hour, short activity, PlayNotificationRequest.VibrationType vibration) {
this.min = min;
this.hour = hour;
this.activity = activity;
this.vibration = vibration;
}
PackageConfig(short min, short hour, String packageName, String appName, boolean respectSilentMode, PlayNotificationRequest.VibrationType vibration, long id) {
this.min = min;
this.hour = hour;
@ -90,6 +97,14 @@ public class PackageConfig implements Serializable {
return hour;
}
public short getActivity() {
return activity;
}
public void setActivity(short activity) {
this.activity = activity;
}
public String getPackageName() {
return packageName;
}

View File

@ -9,7 +9,7 @@ import android.util.Log;
import java.util.ArrayList;
import nodomain.freeyourgadget.gadgetbridge.database.DBOpenHelper;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.PlayNotificationRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.PlayNotificationRequest;
public class PackageConfigHelper extends DBOpenHelper {
public static final String DB_NAME = "qhybridNotifications.db";

View File

@ -12,7 +12,7 @@ import com.twofortyfouram.locale.sdk.client.ui.activity.AbstractPluginActivity;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.PlayNotificationRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.PlayNotificationRequest;
public class TaskerPluginActivity extends AbstractPluginActivity {
public static final String key_hours = "qhybrid_hours";

View File

@ -6,7 +6,7 @@ import android.content.Intent;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.PlayNotificationRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.PlayNotificationRequest;
public class TaskerPluginReceiver extends BroadcastReceiver {

View File

@ -1,7 +1,6 @@
package nodomain.freeyourgadget.gadgetbridge.devices.qhybrid;
import android.app.AlertDialog;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageInfo;
@ -22,7 +21,7 @@ import android.widget.RadioGroup;
import android.widget.ScrollView;
import androidx.annotation.NonNull;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.PlayNotificationRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.PlayNotificationRequest;
public class TimePicker extends AlertDialog.Builder {
ImageView pickerView;

View File

@ -44,31 +44,33 @@ import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
import nodomain.freeyourgadget.gadgetbridge.model.RecordedDataTypes;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.ActivityPointGetRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.AnimationRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.BatteryLevelRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.DownloadFileRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.EraseFileRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.FileRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.GetCountdownSettingsRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.GetCurrentStepCountRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.GetStepGoalRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.GetVibrationStrengthRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.GoalTrackingGetRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.ListFilesRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.MoveHandsRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.OTAEnterRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.OTAEraseRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.PlayNotificationRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.ReleaseHandsControlRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.Request;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.RequestHandControlRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.SetCurrentStepCountRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.SetStepGoalRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.SetTimeRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.SetVibrationStrengthRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.UploadFileRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.VibrateRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.WatchAdapter;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.WatchAdapterFactory;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.ActivityPointGetRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.AnimationRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.BatteryLevelRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.DownloadFileRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.EraseFileRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.FileRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.GetCountdownSettingsRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.GetCurrentStepCountRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.GetStepGoalRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.GetVibrationStrengthRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.GoalTrackingGetRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.ListFilesRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.MoveHandsRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.OTAEnterRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.OTAEraseRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.PlayNotificationRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.ReleaseHandsControlRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.Request;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.RequestHandControlRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.SetCurrentStepCountRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.SetStepGoalRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.SetTimeRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.SetVibrationStrengthRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.UploadFileRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.VibrateRequest;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
public class QHybridSupport extends QHybridBaseSupport {
@ -102,22 +104,14 @@ public class QHybridSupport extends QHybridBaseSupport {
private volatile boolean searchDevice = false;
private int lastButtonIndex = -1;
private final SparseArray<Request> responseFilters = new SparseArray<>();
private Request fileRequest = null;
private long timeOffset;
private UploadFileRequest uploadFileRequest;
private Queue<Request> requestQueue = new ArrayDeque<>();
private String modelNumber;
private boolean useActivityHand;
WatchAdapter watchAdapter;
public QHybridSupport() {
super(logger);
addSupportedService(UUID.fromString("3dda0001-957f-7d4a-34a6-74696673696d"));
@ -133,7 +127,6 @@ public class QHybridSupport extends QHybridBaseSupport {
commandFilter.addAction(QHYBRID_COMMAND_UPDATE_SETTINGS);
commandFilter.addAction(QHYBRID_COMMAND_OVERWRITE_BUTTONS);
LocalBroadcastManager.getInstance(getContext()).registerReceiver(commandReceiver, commandFilter);
fillResponseList();
helper = new PackageConfigHelper(GBApplication.getContext());
@ -162,48 +155,10 @@ public class QHybridSupport extends QHybridBaseSupport {
throw new UnsupportedOperationException();
}
private void fillResponseList() {
Class<? extends Request>[] classes = new Class[]{
BatteryLevelRequest.class,
GetStepGoalRequest.class,
GetVibrationStrengthRequest.class,
GetCurrentStepCountRequest.class,
OTAEnterRequest.class,
GoalTrackingGetRequest.class,
ActivityPointGetRequest.class,
GetCountdownSettingsRequest.class
};
for (Class<? extends Request> c : classes) {
try {
c.getSuperclass().getDeclaredMethod("handleResponse", BluetoothGattCharacteristic.class);
Request object = c.newInstance();
byte[] sequence = object.getStartSequence();
if (sequence.length > 1) {
responseFilters.put((int) object.getStartSequence()[1], object);
Log.d("Service", "response filter " + object.getStartSequence()[1] + ": " + c.getSimpleName());
}
} catch (NoSuchMethodException | IllegalAccessException | InstantiationException e) {
Log.d("Service", "skipping class " + c.getName());
}
}
}
private void getTimeOffset() {
timeOffset = getContext().getSharedPreferences(getContext().getPackageName(), Context.MODE_PRIVATE).getInt("QHYBRID_TIME_OFFSET", 0);
}
private void queueWrite(Request request) {
new TransactionBuilder(request.getClass().getSimpleName()).write(getCharacteristic(request.getRequestUUID()), request.getRequestData()).queue(getQueue());
if (request instanceof FileRequest) this.fileRequest = request;
if (!request.expectsResponse()) {
try {
queueWrite(requestQueue.remove());
} catch (NoSuchElementException e) {
}
}
}
@Override
protected TransactionBuilder initializeDevice(TransactionBuilder builder) {
builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZING, getContext()));
@ -217,43 +172,34 @@ public class QHybridSupport extends QHybridBaseSupport {
for (int i = 2; i <= 7; i++)
builder.notify(getCharacteristic(UUID.fromString("3dda000" + i + "-957f-7d4a-34a6-74696673696d")), true);
requestQueue.add(new GetCurrentStepCountRequest());
requestQueue.add(new GetVibrationStrengthRequest());
requestQueue.add(new ActivityPointGetRequest());
requestQueue.add(prepareSetTimeRequest());
requestQueue.add(new AnimationRequest());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestQueue.add(new SetCurrentStepCountRequest((int) (999999 * calculateNotificationProgress())));
} else {
requestQueue.add(new SetCurrentStepCountRequest(0));
}
Request initialRequest = new GetStepGoalRequest();
builder
// .read(getCharacteristic(UUID.fromString("00002a00-0000-1000-8000-00805f9b34fb")))
.read(getCharacteristic(UUID.fromString("00002a24-0000-1000-8000-00805f9b34fb")))
// .read(getCharacteristic(UUID.fromString("00002a24-0000-1000-8000-00805f9b34fb")))
.read(getCharacteristic(UUID.fromString("00002a26-0000-1000-8000-00805f9b34fb")))
.read(getCharacteristic(UUID.fromString("00002a19-0000-1000-8000-00805f9b34fb")))
.notify(getCharacteristic(UUID.fromString("00002a19-0000-1000-8000-00805f9b34fb")), true)
.write(getCharacteristic(initialRequest.getRequestUUID()), initialRequest.getRequestData());
// .read(getCharacteristic(UUID.fromString("00002a19-0000-1000-8000-00805f9b34fb")))
// .notify(getCharacteristic(UUID.fromString("00002a19-0000-1000-8000-00805f9b34fb")), true)
// .write(getCharacteristic(initialRequest.getRequestUUID()), initialRequest.getRequestData())
;
getTimeOffset();
builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZED, getContext()));
// builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZED, getContext()));
return builder;
}
@Override
public void onFetchRecordedData(int dataTypes) {
if ((dataTypes & RecordedDataTypes.TYPE_ACTIVITY) != 0) {
//TODO
/* if ((dataTypes & RecordedDataTypes.TYPE_ACTIVITY) != 0) {
requestQueue.add(new BatteryLevelRequest());
requestQueue.add(new GetCurrentStepCountRequest());
requestQueue.add(new ListFilesRequest());
queueWrite(new ActivityPointGetRequest());
}
} */
}
@Override
@ -287,19 +233,18 @@ public class QHybridSupport extends QHybridBaseSupport {
}
private void showNotificationsByAllActive(boolean enforceByNotification) {
if(!this.useActivityHand);
if (!this.useActivityHand) ;
double progress = calculateNotificationProgress();
showNotificationCountOnActivityHand(progress);
if(enforceByNotification){
queueWrite(
new PlayNotificationRequest(
PlayNotificationRequest.VibrationType.NO_VIBE,
-1,
-1,
(int) (progress * 180)
)
);
if (enforceByNotification) {
watchAdapter.playNotification(new PackageConfig(
(short) -1,
(short) -1,
//TODO test activity hand
(short) (progress * 180),
PlayNotificationRequest.VibrationType.NO_VIBE
));
}
}
@ -314,7 +259,7 @@ public class QHybridSupport extends QHybridBaseSupport {
for (String notificationPackage : NotificationListener.notificationStack) {
for (PackageConfig packageConfig : configs.keySet()) {
if(configs.get(packageConfig)) continue;
if (configs.get(packageConfig)) continue;
if (packageConfig.getPackageName().equals(notificationPackage)) {
notificationProgress += 0.25;
configs.put(packageConfig, true);
@ -327,27 +272,19 @@ public class QHybridSupport extends QHybridBaseSupport {
private void showNotificationCountOnActivityHand(double progress) {
if (useActivityHand) {
setActivityHand(progress);
watchAdapter.setActivityHand(progress);
}
}
private void playNotification(PackageConfig config) {
if(config.getMin() == -1 && config.getHour() == -1 && config.getVibration() == PlayNotificationRequest.VibrationType.NO_VIBE) return;
queueWrite(new PlayNotificationRequest(config.getVibration(), config.getHour(), config.getMin()));
if (config.getMin() == -1 && config.getHour() == -1 && config.getVibration() == PlayNotificationRequest.VibrationType.NO_VIBE)
return;
watchAdapter.playNotification(config);
}
@Override
public void onSetTime() {
queueWrite(prepareSetTimeRequest());
}
private SetTimeRequest prepareSetTimeRequest() {
long millis = System.currentTimeMillis();
TimeZone zone = new GregorianCalendar().getTimeZone();
return new SetTimeRequest(
(int) (millis / 1000 + timeOffset * 60),
(short) (millis % 1000),
(short) ((zone.getRawOffset() + zone.getDSTSavings()) / 60000));
watchAdapter.setTime();
}
@Override
@ -387,27 +324,7 @@ public class QHybridSupport extends QHybridBaseSupport {
@Override
public void onTestNewFunction() {
float random = (float)Math.random();
setActivityHand(random);
queueWrite(
new PlayNotificationRequest(
PlayNotificationRequest.VibrationType.NO_VIBE,
-1,
-1,
(int) (random * 180)
)
);
}
private void overwriteButtons() {
uploadFileRequest = new UploadFileRequest((short) 0x0800, new byte[]{
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x10, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x0C, (byte) 0x00, (byte) 0x00, (byte) 0x20, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x0C, (byte) 0x00, (byte) 0x00,
(byte) 0x30, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x0C, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x01, (byte) 0x0C, (byte) 0x2E, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01,
(byte) 0x00, (byte) 0x06, (byte) 0x00, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x03, (byte) 0x00, (byte) 0x02, (byte) 0x01, (byte) 0x0F, (byte) 0x00, (byte) 0x8B, (byte) 0x00, (byte) 0x00, (byte) 0x93, (byte) 0x00, (byte) 0x01,
(byte) 0x08, (byte) 0x01, (byte) 0x14, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0xFE, (byte) 0x08, (byte) 0x00, (byte) 0x93, (byte) 0x00, (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0xBF, (byte) 0xD5, (byte) 0x54, (byte) 0xD1,
(byte) 0x00
});
queueWrite(uploadFileRequest);
}
private void backupFile(DownloadFileRequest request) {
@ -430,21 +347,29 @@ public class QHybridSupport extends QHybridBaseSupport {
fos2.write(("file " + request.timeStamp + " cut\n\n").getBytes());
fos2.close();
queueWrite(new EraseFileRequest((short) request.fileHandle));
//TODO file stuff
// queueWrite(new EraseFileRequest((short) request.fileHandle));
} catch (Exception e) {
e.printStackTrace();
if (request.fileHandle > 257) {
queueWrite(new DownloadFileRequest((short) (request.fileHandle - 1)));
// queueWrite(new DownloadFileRequest((short) (request.fileHandle - 1)));
}
}
}
@Override
public void handleGBDeviceEvent(GBDeviceEventBatteryInfo deviceEvent){
super.handleGBDeviceEvent(deviceEvent);
}
@Override
public boolean onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
switch (characteristic.getUuid().toString()) {
case "00002a00-0000-1000-8000-00805f9b34fb": {
String deviceName = characteristic.getStringValue(0);
case "00002a26-0000-1000-8000-00805f9b34fb": {
String firmwareVersion = characteristic.getStringValue(0);
gbDevice.setFirmwareVersion(firmwareVersion);
this.watchAdapter = new WatchAdapterFactory().createWatchAdapter(firmwareVersion, this);
break;
}
case "00002a24-0000-1000-8000-00805f9b34fb": {
@ -460,14 +385,6 @@ public class QHybridSupport extends QHybridBaseSupport {
}
break;
}
case "00002a26-0000-1000-8000-00805f9b34fb": {
String firmwareVersion = characteristic.getStringValue(0);
gbDevice.setFirmwareVersion(firmwareVersion);
checkFirmwareVersion(firmwareVersion);
break;
}
case "00002a19-0000-1000-8000-00805f9b34fb": {
short level = characteristic.getValue()[0];
gbDevice.setBatteryLevel(level);
@ -479,6 +396,7 @@ public class QHybridSupport extends QHybridBaseSupport {
batteryInfo.state = BatteryState.BATTERY_NORMAL;
handleGBDeviceEvent(batteryInfo);
break;
}
}
@ -495,231 +413,10 @@ public class QHybridSupport extends QHybridBaseSupport {
return "unknwon Q";
}
private void checkFirmwareVersion(String firmwareVersion) {
if (!isFirmwareCompatible(firmwareVersion)) {
GB.toast("Firmware " + firmwareVersion + " not compatible", Toast.LENGTH_LONG, GB.ERROR);
getDevice().setName("incopatible firmware");
}
}
private boolean isFirmwareCompatible(String firmwareVersion) {
int major = Integer.parseInt(firmwareVersion.substring(6, 7));
return major == 1;
}
@Override
public boolean onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
switch (characteristic.getUuid().toString()) {
case "3dda0004-957f-7d4a-34a6-74696673696d":
case "3dda0003-957f-7d4a-34a6-74696673696d": {
return handleFileDownloadCharacteristic(characteristic);
}
case "3dda0007-957f-7d4a-34a6-74696673696d": {
return handleFileUploadCharacteristic(characteristic);
}
case "3dda0002-957f-7d4a-34a6-74696673696d": {
return handleBasicCharacteristic(characteristic);
}
case "3dda0006-957f-7d4a-34a6-74696673696d": {
return handleButtonCharacteristic(characteristic);
}
case "00002a19-0000-1000-8000-00805f9b34fb": {
short level = characteristic.getValue()[0];
gbDevice.setBatteryLevel(level);
gbDevice.setBatteryThresholdPercent((short) 2);
GBDeviceEventBatteryInfo batteryInfo = new GBDeviceEventBatteryInfo();
batteryInfo.level = gbDevice.getBatteryLevel();
batteryInfo.state = BatteryState.BATTERY_NORMAL;
handleGBDeviceEvent(batteryInfo);
break;
}
default: {
Log.d("Service", "unknown shit on " + characteristic.getUuid().toString() + ": " + arrayToString(characteristic.getValue()));
try {
File charLog = new File("/sdcard/qFiles/charLog.txt");
if (!charLog.exists()) {
charLog.createNewFile();
}
FileOutputStream fos = new FileOutputStream(charLog, true);
fos.write((new Date().toString() + ": " + characteristic.getUuid().toString() + ": " + arrayToString(characteristic.getValue())).getBytes());
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
return super.onCharacteristicChanged(gatt, characteristic);
}
private void setActivityHand(double progress) {
queueWrite(new SetCurrentStepCountRequest(Math.min((int) (1000000 * progress), 999999)));
}
private boolean handleFileUploadCharacteristic(BluetoothGattCharacteristic characteristic) {
if (uploadFileRequest == null) {
logger.debug("no uploadFileRequest to handle response");
return true;
}
uploadFileRequest.handleResponse(characteristic);
switch (uploadFileRequest.state) {
case ERROR:
Intent fileIntent = new Intent(QHYBRID_EVENT_FILE_UPLOADED);
fileIntent.putExtra("EXTRA_ERROR", true);
LocalBroadcastManager.getInstance(getContext()).sendBroadcast(fileIntent);
uploadFileRequest = null;
break;
case UPLOAD:
for (byte[] packet : this.uploadFileRequest.packets) {
new TransactionBuilder("File upload").write(characteristic, packet).queue(getQueue());
}
break;
case UPLOADED:
fileIntent = new Intent(QHYBRID_EVENT_FILE_UPLOADED);
LocalBroadcastManager.getInstance(getContext()).sendBroadcast(fileIntent);
uploadFileRequest = null;
break;
}
return true;
}
private boolean handleButtonCharacteristic(BluetoothGattCharacteristic characteristic) {
byte[] value = characteristic.getValue();
if (value.length != 11) {
logger.debug("wrong button message");
return true;
}
int index = value[6] & 0xFF;
int button = value[8] >> 4 & 0xFF;
if (index != this.lastButtonIndex) {
lastButtonIndex = index;
logger.debug("Button press on button " + button);
Intent i = new Intent(QHYBRID_EVENT_BUTTON_PRESS);
i.putExtra("BUTTON", button);
//ByteBuffer buffer = ByteBuffer.allocate(16);
//buffer.put(new byte[]{0x01, 0x00, 0x08});
//buffer.put(value, 2, 8);
//buffer.put(new byte[]{(byte)0xFF, 0x05, 0x00, 0x01, 0x00});
//UploadFileRequest request = new UploadFileRequest((short)0, buffer.array());
//for(byte[] packet : request.packets){
// new TransactionBuilder("File upload").write(getCharacteristic(UUID.fromString("3dda0007-957f-7d4a-34a6-74696673696d")), packet).queue(getQueue());
//}
getContext().sendBroadcast(i);
}
return true;
}
private boolean handleBasicCharacteristic(BluetoothGattCharacteristic characteristic) {
byte[] values = characteristic.getValue();
Request request = resolveAnswer(characteristic);
if (request == null) {
StringBuilder valueString = new StringBuilder(String.valueOf(values[0]));
for (int i = 1; i < characteristic.getValue().length; i++) {
valueString.append(", ").append(values[i]);
}
Log.d("Service", "unable to resolve " + characteristic.getUuid().toString() + ": " + valueString);
return true;
}
Log.d("Service", "response: " + request.getClass().getSimpleName());
request.handleResponse(characteristic);
if (request instanceof GetStepGoalRequest) {
gbDevice.addDeviceInfo(new GenericItem(ITEM_STEP_GOAL, String.valueOf(((GetStepGoalRequest) request).stepGoal)));
} else if (request instanceof GetVibrationStrengthRequest) {
int strength = ((GetVibrationStrengthRequest) request).strength;
gbDevice.addDeviceInfo(new GenericItem(ITEM_VIBRATION_STRENGTH, String.valueOf(strength)));
} else if (request instanceof GetCurrentStepCountRequest) {
int steps = ((GetCurrentStepCountRequest) request).steps;
logger.debug("get current steps: " + steps);
try {
File f = new File("/sdcard/qFiles/");
if (!f.exists()) f.mkdir();
File file = new File("/sdcard/qFiles/steps");
if (!file.exists()) {
file.createNewFile();
}
logger.debug("Writing file " + file.getPath());
FileOutputStream fos = new FileOutputStream(file, true);
fos.write((System.currentTimeMillis() + ": " + steps + "\n").getBytes());
fos.close();
logger.debug("file written.");
} catch (Exception e) {
e.printStackTrace();
}
gbDevice.addDeviceInfo(new GenericItem(ITEM_STEP_COUNT, String.valueOf(((GetCurrentStepCountRequest) request).steps)));
} else if (request instanceof OTAEnterRequest) {
if (((OTAEnterRequest) request).success) {
fileRequest = new OTAEraseRequest(1024 << 16);
queueWrite(fileRequest);
}
} else if (request instanceof ActivityPointGetRequest) {
gbDevice.addDeviceInfo(new GenericItem(ITEM_ACTIVITY_POINT, String.valueOf(((ActivityPointGetRequest) request).activityPoint)));
}
try {
queueWrite(requestQueue.remove());
} catch (NoSuchElementException e) {
}
LocalBroadcastManager.getInstance(getContext()).sendBroadcast(new Intent(DeviceManager.ACTION_DEVICES_CHANGED));
return true;
}
private boolean handleFileDownloadCharacteristic(BluetoothGattCharacteristic characteristic) {
Request request;
request = fileRequest;
request.handleResponse(characteristic);
if (request instanceof ListFilesRequest) {
if (((ListFilesRequest) request).completed) {
logger.debug("File count: " + ((ListFilesRequest) request).fileCount + " size: " + ((ListFilesRequest) request).size);
if (((ListFilesRequest) request).fileCount == 0) return true;
// queueWrite(new DownloadFileRequest((short) (256 + ((ListFilesRequest) request).fileCount)));
}
} else if (request instanceof DownloadFileRequest) {
if (((FileRequest) request).completed) {
logger.debug("file " + ((DownloadFileRequest) request).fileHandle + " completed: " + ((DownloadFileRequest) request).size);
backupFile((DownloadFileRequest) request);
}
} else if (request instanceof EraseFileRequest) {
if (((EraseFileRequest) request).fileHandle > 257) {
queueWrite(new DownloadFileRequest((short) (((EraseFileRequest) request).fileHandle - 1)));
}
}
return true;
}
private String arrayToString(byte[] bytes) {
if (bytes.length == 0) return "";
StringBuilder s = new StringBuilder();
final String chars = "0123456789ABCDEF";
for (byte b : bytes) {
s.append(chars.charAt((b >> 4) & 0xF)).append(chars.charAt(b & 0xF)).append(" ");
}
return s.substring(0, s.length() - 1) + "\n";
}
private Request resolveAnswer(BluetoothGattCharacteristic characteristic) {
byte[] values = characteristic.getValue();
if (values[0] != 3) return null;
return responseFilters.get(values[1]);
}
private void setHands(short hour, short minute) {
queueWrite(new MoveHandsRequest(false, minute, hour, (short) -1));
}
private void vibrate(PlayNotificationRequest.VibrationType vibration) {
queueWrite(new PlayNotificationRequest(vibration, -1, -1));
public boolean onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic
characteristic) {
return watchAdapter.onCharacteristicChanged(gatt, characteristic);
}
private final BroadcastReceiver globalCommandReceiver = new BroadcastReceiver() {
@ -730,16 +427,14 @@ public class QHybridSupport extends QHybridBaseSupport {
try {
Object extra = intent.getExtras().get("EXTRA_PROGRESS");
float progress = (float) extra;
setActivityHand(progress);
watchAdapter.setActivityHand(progress);
queueWrite(
new PlayNotificationRequest(
PlayNotificationRequest.VibrationType.NO_VIBE,
-1,
-1,
(int) (progress * 180)
)
);
watchAdapter.playNotification(new PackageConfig(
(short) -1,
(short) -1,
(short) (progress * 180),
PlayNotificationRequest.VibrationType.NO_VIBE
));
} catch (Exception e) {
e.printStackTrace();
logger.debug("trash extra should be number 0.0-1.0");
@ -759,29 +454,29 @@ public class QHybridSupport extends QHybridBaseSupport {
switch (intent.getAction()) {
case QHYBRID_COMMAND_CONTROL: {
Log.d("Service", "sending control request");
queueWrite(new RequestHandControlRequest());
watchAdapter.requestHandsControl();
if (config != null) {
setHands(config.getHour(), config.getMin());
watchAdapter.setHands(config.getHour(), config.getMin());
} else {
setHands((short) 0, (short) 0);
watchAdapter.setHands((short) 0, (short) 0);
}
break;
}
case QHYBRID_COMMAND_UNCONTROL: {
queueWrite(new ReleaseHandsControlRequest());
watchAdapter.releaseHandsControl();
break;
}
case QHYBRID_COMMAND_SET: {
setHands(config.getHour(), config.getMin());
watchAdapter.setHands(config.getHour(), config.getMin());
break;
}
case QHYBRID_COMMAND_VIBRATE: {
vibrate(config.getVibration());
watchAdapter.vibrate(config.getVibration());
break;
}
case QHYBRID_COMMAND_NOTIFICATION: {
queueWrite(new PlayNotificationRequest(config.getVibration(), config.getHour(), config.getMin()));
watchAdapter.playNotification(config);
break;
}
case QHYBRID_COMMAND_UPDATE: {
@ -793,12 +488,12 @@ public class QHybridSupport extends QHybridBaseSupport {
String newSetting = intent.getStringExtra("EXTRA_SETTING");
switch (newSetting) {
case ITEM_VIBRATION_STRENGTH: {
queueWrite(new SetVibrationStrengthRequest(Short.parseShort(gbDevice.getDeviceInfo(ITEM_VIBRATION_STRENGTH).getDetails())));
watchAdapter.setVibrationStrength(Short.parseShort(gbDevice.getDeviceInfo(ITEM_VIBRATION_STRENGTH).getDetails()));
// queueWrite(new VibrateRequest(false, (short)4, (short)1));
break;
}
case ITEM_STEP_GOAL: {
queueWrite(new SetStepGoalRequest(Integer.parseInt(gbDevice.getDeviceInfo(ITEM_STEP_GOAL).getDetails())));
watchAdapter.setStepGoal(Integer.parseInt(gbDevice.getDeviceInfo(ITEM_STEP_GOAL).getDetails()));
break;
}
case ITEM_USE_ACTIVITY_HAND: {
@ -812,7 +507,7 @@ public class QHybridSupport extends QHybridBaseSupport {
break;
}
case QHYBRID_COMMAND_OVERWRITE_BUTTONS: {
overwriteButtons();
watchAdapter.overwriteButtons();
break;
}
}

View File

@ -0,0 +1,46 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.content.Context;
import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.PackageConfig;
import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.misfit.MisfitWatchAdapter;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.PlayNotificationRequest;
public abstract class WatchAdapter {
private QHybridSupport deviceSupport;
public WatchAdapter(QHybridSupport deviceSupport){
this.deviceSupport = deviceSupport;
}
protected QHybridSupport getDeviceSupport(){
return this.deviceSupport;
}
protected Context getContext(){
return getDeviceSupport().getContext();
}
public abstract void initialize();
public abstract void playPairingAnimation();
public abstract void playNotification(PackageConfig config);
public abstract void setTime();
public abstract void overwriteButtons();
public abstract void setActivityHand(double progress);
public abstract void setHands(short hour, short minute);
public abstract void vibrate(PlayNotificationRequest.VibrationType vibration);
public abstract void requestHandsControl();
public abstract void releaseHandsControl();
public abstract void setStepGoal(int stepGoal);
public abstract void setVibrationStrength(short strength);
public abstract boolean onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic);
}

View File

@ -0,0 +1,16 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter;
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.misfit.MisfitWatchAdapter;
public final class WatchAdapterFactory {
public final WatchAdapter createWatchAdapter(String firmwareVersion, QHybridSupport deviceSupport){
char major = firmwareVersion.charAt(6);
switch (major){
case 'a': return new MisfitWatchAdapter(deviceSupport);
}
throw new UnsupportedOperationException("Firmware " + firmwareVersion + " not supported");
}
}

View File

@ -0,0 +1,419 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.misfit;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.content.Intent;
import android.os.Build;
import android.util.Log;
import android.util.SparseArray;
import android.widget.Toast;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.NoSuchElementException;
import java.util.Queue;
import java.util.TimeZone;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo;
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceManager;
import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.PackageConfig;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.BatteryState;
import nodomain.freeyourgadget.gadgetbridge.model.GenericItem;
import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.WatchAdapter;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.ActivityPointGetRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.AnimationRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.BatteryLevelRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.DownloadFileRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.EraseFileRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.FileRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.GetCountdownSettingsRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.GetCurrentStepCountRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.GetStepGoalRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.GetVibrationStrengthRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.GoalTrackingGetRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.ListFilesRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.MoveHandsRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.OTAEnterRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.OTAEraseRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.PlayNotificationRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.ReleaseHandsControlRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.Request;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.RequestHandControlRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.SetCurrentStepCountRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.SetStepGoalRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.SetTimeRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.SetVibrationStrengthRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.UploadFileRequest;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
import static nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport.ITEM_ACTIVITY_POINT;
import static nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport.ITEM_STEP_COUNT;
import static nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport.ITEM_STEP_GOAL;
import static nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport.ITEM_VIBRATION_STRENGTH;
import static nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport.QHYBRID_EVENT_BUTTON_PRESS;
import static nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport.QHYBRID_EVENT_FILE_UPLOADED;
public class MisfitWatchAdapter extends WatchAdapter {
private int lastButtonIndex = -1;
private final SparseArray<Request> responseFilters = new SparseArray<>();
private static final Logger logger = LoggerFactory.getLogger(QHybridSupport.class);
private UploadFileRequest uploadFileRequest;
private Request fileRequest = null;
private Queue<Request> requestQueue = new ArrayDeque<>();
public MisfitWatchAdapter(QHybridSupport deviceSupport) {
super(deviceSupport);
fillResponseList();
}
@Override
public void initialize() {
requestQueue.add(new GetCurrentStepCountRequest());
requestQueue.add(new GetVibrationStrengthRequest());
requestQueue.add(new ActivityPointGetRequest());
requestQueue.add(prepareSetTimeRequest());
requestQueue.add(new AnimationRequest());
//TODO
// requestQueue.add(new SetCurrentStepCountRequest((int) (999999 * calculateNotificationProgress())));
}
private SetTimeRequest prepareSetTimeRequest() {
long millis = System.currentTimeMillis();
TimeZone zone = new GregorianCalendar().getTimeZone();
return new SetTimeRequest(
//TODO time offset
(int) (millis / 1000 + 0 * 60),
(short) (millis % 1000),
(short) ((zone.getRawOffset() + zone.getDSTSavings()) / 60000));
}
@Override
public void playPairingAnimation() {
queueWrite(new AnimationRequest());
}
@Override
public void playNotification(PackageConfig config) {
queueWrite(new PlayNotificationRequest(
config.getVibration(),
config.getHour(),
config.getMin()
));
}
@Override
public void setTime() {
}
@Override
public boolean onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
GBDevice gbDevice = getDeviceSupport().getDevice();
switch (characteristic.getUuid().toString()) {
case "3dda0004-957f-7d4a-34a6-74696673696d":
case "3dda0003-957f-7d4a-34a6-74696673696d": {
return handleFileDownloadCharacteristic(characteristic);
}
case "3dda0007-957f-7d4a-34a6-74696673696d": {
return handleFileUploadCharacteristic(characteristic);
}
case "3dda0002-957f-7d4a-34a6-74696673696d": {
return handleBasicCharacteristic(characteristic);
}
case "3dda0006-957f-7d4a-34a6-74696673696d": {
return handleButtonCharacteristic(characteristic);
}
case "00002a19-0000-1000-8000-00805f9b34fb": {
short level = characteristic.getValue()[0];
gbDevice.setBatteryLevel(level);
gbDevice.setBatteryThresholdPercent((short) 2);
GBDeviceEventBatteryInfo batteryInfo = new GBDeviceEventBatteryInfo();
batteryInfo.level = gbDevice.getBatteryLevel();
batteryInfo.state = BatteryState.BATTERY_NORMAL;
getDeviceSupport().handleGBDeviceEvent(batteryInfo);
break;
}
default: {
Log.d("Service", "unknown shit on " + characteristic.getUuid().toString() + ": " + arrayToString(characteristic.getValue()));
try {
File charLog = new File("/sdcard/qFiles/charLog.txt");
if (!charLog.exists()) {
charLog.createNewFile();
}
FileOutputStream fos = new FileOutputStream(charLog, true);
fos.write((new Date().toString() + ": " + characteristic.getUuid().toString() + ": " + arrayToString(characteristic.getValue())).getBytes());
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
return getDeviceSupport().onCharacteristicChanged(gatt, characteristic);
}
private String arrayToString(byte[] bytes) {
if (bytes.length == 0) return "";
StringBuilder s = new StringBuilder();
final String chars = "0123456789ABCDEF";
for (byte b : bytes) {
s.append(chars.charAt((b >> 4) & 0xF)).append(chars.charAt(b & 0xF)).append(" ");
}
return s.substring(0, s.length() - 1) + "\n";
}
private void fillResponseList() {
Class<? extends Request>[] classes = new Class[]{
BatteryLevelRequest.class,
GetStepGoalRequest.class,
GetVibrationStrengthRequest.class,
GetCurrentStepCountRequest.class,
OTAEnterRequest.class,
GoalTrackingGetRequest.class,
ActivityPointGetRequest.class,
GetCountdownSettingsRequest.class
};
for (Class<? extends Request> c : classes) {
try {
c.getSuperclass().getDeclaredMethod("handleResponse", BluetoothGattCharacteristic.class);
Request object = c.newInstance();
byte[] sequence = object.getStartSequence();
if (sequence.length > 1) {
responseFilters.put((int) object.getStartSequence()[1], object);
Log.d("Service", "response filter " + object.getStartSequence()[1] + ": " + c.getSimpleName());
}
} catch (NoSuchMethodException | IllegalAccessException | InstantiationException e) {
Log.d("Service", "skipping class " + c.getName());
}
}
}
private boolean handleBasicCharacteristic(BluetoothGattCharacteristic characteristic) {
byte[] values = characteristic.getValue();
Request request = resolveAnswer(characteristic);
GBDevice gbDevice = getDeviceSupport().getDevice();
if (request == null) {
StringBuilder valueString = new StringBuilder(String.valueOf(values[0]));
for (int i = 1; i < characteristic.getValue().length; i++) {
valueString.append(", ").append(values[i]);
}
Log.d("Service", "unable to resolve " + characteristic.getUuid().toString() + ": " + valueString);
return true;
}
Log.d("Service", "response: " + request.getClass().getSimpleName());
request.handleResponse(characteristic);
if (request instanceof GetStepGoalRequest) {
gbDevice.addDeviceInfo(new GenericItem(ITEM_STEP_GOAL, String.valueOf(((GetStepGoalRequest) request).stepGoal)));
} else if (request instanceof GetVibrationStrengthRequest) {
int strength = ((GetVibrationStrengthRequest) request).strength;
gbDevice.addDeviceInfo(new GenericItem(ITEM_VIBRATION_STRENGTH, String.valueOf(strength)));
} else if (request instanceof GetCurrentStepCountRequest) {
int steps = ((GetCurrentStepCountRequest) request).steps;
logger.debug("get current steps: " + steps);
try {
File f = new File("/sdcard/qFiles/");
if (!f.exists()) f.mkdir();
File file = new File("/sdcard/qFiles/steps");
if (!file.exists()) {
file.createNewFile();
}
logger.debug("Writing file " + file.getPath());
FileOutputStream fos = new FileOutputStream(file, true);
fos.write((System.currentTimeMillis() + ": " + steps + "\n").getBytes());
fos.close();
logger.debug("file written.");
} catch (Exception e) {
e.printStackTrace();
}
gbDevice.addDeviceInfo(new GenericItem(ITEM_STEP_COUNT, String.valueOf(((GetCurrentStepCountRequest) request).steps)));
} else if (request instanceof OTAEnterRequest) {
if (((OTAEnterRequest) request).success) {
fileRequest = new OTAEraseRequest(1024 << 16);
queueWrite(fileRequest);
}
} else if (request instanceof ActivityPointGetRequest) {
gbDevice.addDeviceInfo(new GenericItem(ITEM_ACTIVITY_POINT, String.valueOf(((ActivityPointGetRequest) request).activityPoint)));
}
try {
queueWrite(requestQueue.remove());
} catch (NoSuchElementException e) {
}
LocalBroadcastManager.getInstance(getContext()).sendBroadcast(new Intent(DeviceManager.ACTION_DEVICES_CHANGED));
return true;
}
private Request resolveAnswer(BluetoothGattCharacteristic characteristic) {
byte[] values = characteristic.getValue();
if (values[0] != 3) return null;
return responseFilters.get(values[1]);
}
private boolean handleFileDownloadCharacteristic(BluetoothGattCharacteristic characteristic) {
Request request;
request = fileRequest;
request.handleResponse(characteristic);
if (request instanceof ListFilesRequest) {
if (((ListFilesRequest) request).completed) {
logger.debug("File count: " + ((ListFilesRequest) request).fileCount + " size: " + ((ListFilesRequest) request).size);
if (((ListFilesRequest) request).fileCount == 0) return true;
// queueWrite(new DownloadFileRequest((short) (256 + ((ListFilesRequest) request).fileCount)));
}
} else if (request instanceof DownloadFileRequest) {
if (((FileRequest) request).completed) {
logger.debug("file " + ((DownloadFileRequest) request).fileHandle + " completed: " + ((DownloadFileRequest) request).size);
// backupFile((DownloadFileRequest) request);
}
} else if (request instanceof EraseFileRequest) {
if (((EraseFileRequest) request).fileHandle > 257) {
queueWrite(new DownloadFileRequest((short) (((EraseFileRequest) request).fileHandle - 1)));
}
}
return true;
}
private boolean handleFileUploadCharacteristic(BluetoothGattCharacteristic characteristic) {
if (uploadFileRequest == null) {
logger.debug("no uploadFileRequest to handle response");
return true;
}
uploadFileRequest.handleResponse(characteristic);
switch (uploadFileRequest.state) {
case ERROR:
Intent fileIntent = new Intent(QHYBRID_EVENT_FILE_UPLOADED);
fileIntent.putExtra("EXTRA_ERROR", true);
LocalBroadcastManager.getInstance(getContext()).sendBroadcast(fileIntent);
uploadFileRequest = null;
break;
case UPLOAD:
for (byte[] packet : this.uploadFileRequest.packets) {
new TransactionBuilder("File upload").write(characteristic, packet).queue(getDeviceSupport().getQueue());
}
break;
case UPLOADED:
fileIntent = new Intent(QHYBRID_EVENT_FILE_UPLOADED);
LocalBroadcastManager.getInstance(getContext()).sendBroadcast(fileIntent);
uploadFileRequest = null;
break;
}
return true;
}
private boolean handleButtonCharacteristic(BluetoothGattCharacteristic characteristic) {
byte[] value = characteristic.getValue();
if (value.length != 11) {
logger.debug("wrong button message");
return true;
}
int index = value[6] & 0xFF;
int button = value[8] >> 4 & 0xFF;
if (index != this.lastButtonIndex) {
lastButtonIndex = index;
logger.debug("Button press on button " + button);
Intent i = new Intent(QHYBRID_EVENT_BUTTON_PRESS);
i.putExtra("BUTTON", button);
//ByteBuffer buffer = ByteBuffer.allocate(16);
//buffer.put(new byte[]{0x01, 0x00, 0x08});
//buffer.put(value, 2, 8);
//buffer.put(new byte[]{(byte)0xFF, 0x05, 0x00, 0x01, 0x00});
//UploadFileRequest request = new UploadFileRequest((short)0, buffer.array());
//for(byte[] packet : request.packets){
// new TransactionBuilder("File upload").write(getCharacteristic(UUID.fromString("3dda0007-957f-7d4a-34a6-74696673696d")), packet).queue(getQueue());
//}
getContext().sendBroadcast(i);
}
return true;
}
public void setActivityHand(double progress) {
queueWrite(new SetCurrentStepCountRequest(Math.min((int) (1000000 * progress), 999999)));
}
public void setHands(short hour, short minute) {
queueWrite(new MoveHandsRequest(false, minute, hour, (short) -1));
}
public void vibrate(PlayNotificationRequest.VibrationType vibration) {
queueWrite(new PlayNotificationRequest(vibration, -1, -1));
}
@Override
public void requestHandsControl() {
queueWrite(new RequestHandControlRequest());
}
@Override
public void releaseHandsControl() {
queueWrite(new ReleaseHandsControlRequest());
}
@Override
public void setStepGoal(int stepGoal) {
queueWrite(new SetStepGoalRequest(stepGoal));
}
@Override
public void setVibrationStrength(short strength) {
queueWrite(new SetVibrationStrengthRequest(strength));
}
@Override
public void overwriteButtons() {
uploadFileRequest = new UploadFileRequest((short) 0x0800, new byte[]{
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x10, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x0C, (byte) 0x00, (byte) 0x00, (byte) 0x20, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x0C, (byte) 0x00, (byte) 0x00,
(byte) 0x30, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x0C, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x01, (byte) 0x0C, (byte) 0x2E, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01,
(byte) 0x00, (byte) 0x06, (byte) 0x00, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x03, (byte) 0x00, (byte) 0x02, (byte) 0x01, (byte) 0x0F, (byte) 0x00, (byte) 0x8B, (byte) 0x00, (byte) 0x00, (byte) 0x93, (byte) 0x00, (byte) 0x01,
(byte) 0x08, (byte) 0x01, (byte) 0x14, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0xFE, (byte) 0x08, (byte) 0x00, (byte) 0x93, (byte) 0x00, (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0xBF, (byte) 0xD5, (byte) 0x54, (byte) 0xD1,
(byte) 0x00
});
queueWrite(uploadFileRequest);
}
private void queueWrite(Request request) {
new TransactionBuilder(request.getClass().getSimpleName()).write(getDeviceSupport().getCharacteristic(request.getRequestUUID()), request.getRequestData()).queue(getDeviceSupport().getQueue());
// if (request instanceof FileRequest) this.fileRequest = request;
if (!request.expectsResponse()) {
try {
queueWrite(requestQueue.remove());
} catch (NoSuchElementException e) {
}
}
}
}

View File

@ -1,4 +1,4 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
import android.bluetooth.BluetoothGattCharacteristic;

View File

@ -1,4 +1,4 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
public class AnimationRequest extends Request{
@Override

View File

@ -1,4 +1,4 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
import android.bluetooth.BluetoothGattCharacteristic;

View File

@ -1,10 +1,9 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
import android.bluetooth.BluetoothGattCharacteristic;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.UUID;
import java.util.zip.CRC32;
public class DownloadFileRequest extends FileRequest {

View File

@ -1,11 +1,10 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
import android.bluetooth.BluetoothGattCharacteristic;
import android.util.Log;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.UUID;
public class EraseFileRequest extends FileRequest{
public short fileHandle, deletedHandle;

View File

@ -1,4 +1,4 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
import java.nio.ByteBuffer;
import java.util.UUID;

View File

@ -1,4 +1,4 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
import java.util.UUID;

View File

@ -1,4 +1,4 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
import android.bluetooth.BluetoothGattCharacteristic;
import android.util.Log;

View File

@ -1,4 +1,4 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
import android.bluetooth.BluetoothGattCharacteristic;

View File

@ -1,4 +1,4 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
import android.bluetooth.BluetoothGattCharacteristic;

View File

@ -1,4 +1,4 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
public class GetTripleTapEnabledRequest extends Request {
@Override

View File

@ -1,4 +1,4 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
import android.bluetooth.BluetoothGattCharacteristic;

View File

@ -1,4 +1,4 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
import android.bluetooth.BluetoothGattCharacteristic;

View File

@ -1,4 +1,4 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
public class GoalTrackingSetRequest extends Request {
public GoalTrackingSetRequest(int id, boolean state) {

View File

@ -1,12 +1,9 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
import android.bluetooth.BluetoothGattCharacteristic;
import android.util.Log;
import android.util.SparseArray;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.UUID;
public class ListFilesRequest extends FileRequest{
public int fileCount = -1;

View File

@ -1,4 +1,4 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
import java.nio.ByteBuffer;

View File

@ -1,4 +1,4 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
import android.bluetooth.BluetoothGattCharacteristic;

View File

@ -1,4 +1,4 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
import android.bluetooth.BluetoothGattCharacteristic;

View File

@ -1,4 +1,4 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
public class OTAResetRequest extends Request {
@Override

View File

@ -1,4 +1,4 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
import java.nio.ByteBuffer;
import java.security.InvalidParameterException;

View File

@ -1,4 +1,4 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
public class PutSettingsFileRequest extends Request {
@Override

View File

@ -1,8 +1,7 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class ReleaseHandsControlRequest extends Request {
public ReleaseHandsControlRequest(){

View File

@ -1,4 +1,4 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
import android.bluetooth.BluetoothGattCharacteristic;
import android.util.Log;

View File

@ -1,8 +1,7 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class RequestHandControlRequest extends Request {
public RequestHandControlRequest(byte priority, boolean moveCompleteNotify, boolean controlLostNOtify){

View File

@ -1,4 +1,4 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
import java.nio.ByteBuffer;

View File

@ -1,4 +1,4 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
import java.nio.ByteBuffer;

View File

@ -1,7 +1,6 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class SetCurrentTimeServiceRequest extends Request {
public SetCurrentTimeServiceRequest(int timeStampSecs, short millis, short offsetInMins){

View File

@ -1,7 +1,6 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class SetStepGoalRequest extends Request {
public SetStepGoalRequest(int goal){

View File

@ -1,4 +1,4 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
import java.nio.ByteBuffer;

View File

@ -1,4 +1,4 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
public class SetTripleTapEnabledRequest extends Request{
@Override

View File

@ -1,8 +1,7 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class SetVibrationStrengthRequest extends Request {
public SetVibrationStrengthRequest(short strength){

View File

@ -1,4 +1,4 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
import java.nio.ByteBuffer;
import java.util.UUID;

View File

@ -1,4 +1,4 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
import android.bluetooth.BluetoothGattCharacteristic;
@ -8,8 +8,6 @@ import java.util.ArrayList;
import java.util.UUID;
import java.util.zip.CRC32;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
public class UploadFileRequest extends Request {
public enum UploadState{INITIALIZED, UPLOAD, UPLOADED, ERROR}

View File

@ -1,4 +1,4 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests;
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit;
import java.nio.ByteBuffer;