mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2025-01-11 01:21:56 +01:00
Fix watch init (only do the bare minimum) and add basic
notification support. Reconnect is WiP.
This commit is contained in:
parent
b653789b66
commit
92986724ee
@ -89,7 +89,7 @@ public final class CasioConstants {
|
||||
public static final UUID CASIO_SETTING_FOR_BLE_CHARACTERISTIC_UUID = UUID.fromString("26eb000f-b012-49a8-b1f8-394fb2032b0f");
|
||||
public static final UUID CASIO_SETTING_FOR_ALM_CHARACTERISTIC_UUID = UUID.fromString("26eb0013-b012-49a8-b1f8-394fb2032b0f");
|
||||
|
||||
// Notification Types
|
||||
// Notification Types - GB6900
|
||||
|
||||
public static final byte CALL_NOTIFICATION_ID = 3;
|
||||
public static final byte MAIL_NOTIFICATION_ID = 1;
|
||||
@ -97,6 +97,22 @@ public final class CasioConstants {
|
||||
public static final byte SNS_NOTIFICATION_ID = 13;
|
||||
public static final byte SMS_NOTIFICATION_ID = 5;
|
||||
|
||||
// Notification Types - GBX100
|
||||
public static final byte CATEGORY_ADVERTISEMENT = 13;
|
||||
public static final byte CATEGORY_BUSINESS = 9;
|
||||
public static final byte CATEGORY_CONDITION = 12;
|
||||
public static final byte CATEGORY_EMAIL = 6;
|
||||
public static final byte CATEGORY_ENTERTAINMENT = 11;
|
||||
public static final byte CATEGORY_HEATH_AND_FITNESS = 8;
|
||||
public static final byte CATEGORY_INCOMING_CALL = 1;
|
||||
public static final byte CATEGORY_LOCATION = 10;
|
||||
public static final byte CATEGORY_MISSED_CALL = 2;
|
||||
public static final byte CATEGORY_NEWS = 7;
|
||||
public static final byte CATEGORY_OTHER = 0;
|
||||
public static final byte CATEGORY_SCHEDULE_AND_ALARM = 5;
|
||||
public static final byte CATEGORY_SNS = 4;
|
||||
public static final byte CATEGORY_VOICEMAIL = 3;
|
||||
|
||||
public enum Model {
|
||||
MODEL_CASIO_GENERIC,
|
||||
MODEL_CASIO_6900B,
|
||||
|
@ -359,6 +359,16 @@ public final class BtLEQueue {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aborts the currently running transaction
|
||||
*/
|
||||
public void abortCurrentTransaction() {
|
||||
mAbortTransaction = true;
|
||||
if (mWaitForActionResultLatch != null) {
|
||||
mWaitForActionResultLatch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a serverTransaction to the end of the queue
|
||||
*
|
||||
|
@ -31,6 +31,7 @@ import org.slf4j.LoggerFactory;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@ -82,9 +83,8 @@ public class CasioGBX100DeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
}
|
||||
*/
|
||||
|
||||
public void setInitialized() {
|
||||
gbDevice.setState(GBDevice.State.INITIALIZED);
|
||||
gbDevice.sendDeviceUpdateIntent(getContext());
|
||||
public void setInitialized(TransactionBuilder builder) {
|
||||
builder.add(new SetDeviceStateAction(gbDevice, GBDevice.State.INITIALIZED, getContext()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -143,24 +143,91 @@ public class CasioGBX100DeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void showNotification(byte icon, String title, String message, int id) {
|
||||
byte[] titleBytes = title.getBytes(StandardCharsets.UTF_8);
|
||||
byte[] messageBytes = message.getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
byte[] arr = new byte[22];
|
||||
arr[0] = (byte) 0x03; // (byte)(id & 0xff);
|
||||
arr[1] = (byte) 0x00; //((id >> 8) & 0xff);
|
||||
arr[2] = (byte) 0x00; // ((id >> 16) & 0xff);
|
||||
arr[3] = (byte) 0x00; // ((id >> 24) & 0xff);
|
||||
arr[4] = 0x00;
|
||||
arr[5] = (byte) 0x01;
|
||||
arr[6] = icon;
|
||||
arr[7] = (byte) 0x32;
|
||||
arr[8] = (byte) 0x30;
|
||||
arr[9] = (byte) 0x32;
|
||||
arr[10] = (byte) 0x30;
|
||||
arr[11] = (byte) 0x31;
|
||||
arr[12] = (byte) 0x31;
|
||||
arr[13] = (byte) 0x31;
|
||||
arr[14] = (byte) 0x33;
|
||||
arr[15] = (byte) 0x54;
|
||||
arr[16] = (byte) 0x30;
|
||||
arr[17] = (byte) 0x39;
|
||||
arr[18] = (byte) 0x33;
|
||||
arr[19] = (byte) 0x31;
|
||||
arr[20] = (byte) 0x35;
|
||||
arr[21] = (byte) 0x33;
|
||||
byte[] copy = Arrays.copyOf(arr, arr.length + 2);
|
||||
copy[copy.length-2] = 0;
|
||||
copy[copy.length-1] = 0;
|
||||
// appName is currently not supported
|
||||
copy = Arrays.copyOf(copy, copy.length + 2);
|
||||
copy[copy.length-2] = 0;
|
||||
copy[copy.length-1] = 0;
|
||||
if(titleBytes.length > 0) {
|
||||
copy = Arrays.copyOf(copy, copy.length + titleBytes.length);
|
||||
copy[copy.length-2-titleBytes.length] = (byte)(titleBytes.length & 0xff);
|
||||
copy[copy.length-1-titleBytes.length] = (byte)((titleBytes.length >> 8) & 0xff);
|
||||
System.arraycopy(titleBytes, 0, copy, copy.length - titleBytes.length, titleBytes.length);
|
||||
}
|
||||
copy = Arrays.copyOf(copy, copy.length + 2);
|
||||
copy[copy.length-2] = 0;
|
||||
copy[copy.length-1] = 0;
|
||||
//subtitle is currently not supported
|
||||
copy = Arrays.copyOf(copy, copy.length + 2);
|
||||
copy[copy.length-2] = 0;
|
||||
copy[copy.length-1] = 0;
|
||||
if(messageBytes.length > 0) {
|
||||
copy = Arrays.copyOf(copy, copy.length + messageBytes.length);
|
||||
copy[copy.length-2-messageBytes.length] = (byte)(messageBytes.length & 0xff);
|
||||
copy[copy.length-1-messageBytes.length] = (byte)((messageBytes.length >> 8) & 0xff);
|
||||
System.arraycopy(messageBytes, 0, copy, copy.length - messageBytes.length, messageBytes.length);
|
||||
}
|
||||
for(int i=0; i<copy.length; i++) {
|
||||
copy[i] = (byte)(~copy[i]);
|
||||
}
|
||||
|
||||
try {
|
||||
TransactionBuilder builder = performInitialized("showNotification");
|
||||
builder.write(getCharacteristic(CasioConstants.CASIO_NOTIFICATION_CHARACTERISTIC_UUID), copy);
|
||||
LOG.info("Showing notification, title: " + title + " message (not sent): " + message);
|
||||
builder.queue(getQueue());
|
||||
} catch (IOException e) {
|
||||
LOG.warn("showNotification failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onNotification(NotificationSpec notificationSpec) {
|
||||
String notificationTitle = StringUtils.getFirstOf(notificationSpec.sender, notificationSpec.title);
|
||||
byte icon;
|
||||
switch (notificationSpec.type) {
|
||||
case GENERIC_SMS:
|
||||
icon = CasioConstants.SMS_NOTIFICATION_ID;
|
||||
icon = CasioConstants.CATEGORY_EMAIL;
|
||||
break;
|
||||
case GENERIC_CALENDAR:
|
||||
icon = CasioConstants.CALENDAR_NOTIFICATION_ID;
|
||||
icon = CasioConstants.CATEGORY_SCHEDULE_AND_ALARM;
|
||||
break;
|
||||
case GENERIC_EMAIL:
|
||||
icon = CasioConstants.MAIL_NOTIFICATION_ID;
|
||||
icon = CasioConstants.CATEGORY_EMAIL;
|
||||
break;
|
||||
default:
|
||||
icon = CasioConstants.SNS_NOTIFICATION_ID;
|
||||
icon = CasioConstants.CATEGORY_SNS;
|
||||
break;
|
||||
}
|
||||
showNotification(icon, notificationTitle, notificationSpec.body, notificationSpec.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -180,7 +247,14 @@ public class CasioGBX100DeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
|
||||
@Override
|
||||
public void onSetCallState(CallSpec callSpec) {
|
||||
|
||||
switch (callSpec.command) {
|
||||
case CallSpec.CALL_INCOMING:
|
||||
showNotification(CasioConstants.CATEGORY_INCOMING_CALL, callSpec.name, callSpec.number, 0x9876);
|
||||
break;
|
||||
default:
|
||||
LOG.info("not sending CallSpec since only CALL_INCOMING is handled");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -77,12 +77,19 @@ public class InitOperationGBX100 extends AbstractBTLEOperation<CasioGBX100Device
|
||||
}
|
||||
}
|
||||
|
||||
private void writeAllFeaturesInit() {
|
||||
private void writeAllFeaturesInit(TransactionBuilder builder) {
|
||||
byte[] arr = new byte[2];
|
||||
arr[0] = 0x00;
|
||||
arr[1] = 0x01;
|
||||
|
||||
writeAllFeatures(arr);
|
||||
if(builder != null)
|
||||
writeAllFeatures(builder, arr);
|
||||
else
|
||||
writeAllFeatures(arr);
|
||||
}
|
||||
|
||||
private void writeAllFeaturesInit() {
|
||||
writeAllFeaturesInit(null);
|
||||
}
|
||||
|
||||
private void requestWatchName(TransactionBuilder builder) {
|
||||
@ -129,7 +136,7 @@ public class InitOperationGBX100 extends AbstractBTLEOperation<CasioGBX100Device
|
||||
writeAllFeaturesRequest(new byte[]{CasioConstants.characteristicToByte.get("CASIO_DST_SETTING")});
|
||||
}
|
||||
|
||||
private void writeWatchName() {
|
||||
private void writeAppInformation() {
|
||||
// FIXME: The App ID should be auto-generated and stored in the
|
||||
// preferences instead of hard-coding it here
|
||||
// CASIO_APP_INFORMATION:
|
||||
@ -244,7 +251,7 @@ public class InitOperationGBX100 extends AbstractBTLEOperation<CasioGBX100Device
|
||||
writeAllFeatures(arr);
|
||||
}
|
||||
|
||||
private void writeCurrentTime() {
|
||||
private void writeCurrentTime(TransactionBuilder builder) {
|
||||
byte[] arr = new byte[11];
|
||||
Calendar cal = Calendar.getInstance();
|
||||
|
||||
@ -264,7 +271,10 @@ public class InitOperationGBX100 extends AbstractBTLEOperation<CasioGBX100Device
|
||||
arr[9] = (byte)(int) TimeUnit.MILLISECONDS.toSeconds(256 * cal.get(Calendar.MILLISECOND));
|
||||
arr[10] = 1; // or 0?
|
||||
|
||||
writeAllFeatures(arr);
|
||||
if(builder == null)
|
||||
writeAllFeatures(arr);
|
||||
else
|
||||
writeAllFeatures(builder, arr);
|
||||
}
|
||||
|
||||
private void enableAllFeatures(boolean enable) {
|
||||
@ -288,7 +298,6 @@ public class InitOperationGBX100 extends AbstractBTLEOperation<CasioGBX100Device
|
||||
builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZING, getContext()));
|
||||
enableAllFeatures(builder, true);
|
||||
requestWatchName(builder);
|
||||
//writeAllFeaturesInit();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -308,8 +317,10 @@ public class InitOperationGBX100 extends AbstractBTLEOperation<CasioGBX100Device
|
||||
if(characteristicUUID.equals(CasioConstants.CASIO_ALL_FEATURES_CHARACTERISTIC_UUID)) {
|
||||
if(data[0] == CasioConstants.characteristicToByte.get("CASIO_WATCH_NAME")) {
|
||||
LOG.info("Got watch name, requesting BLE features; should write CASIO_APP_INFORMATION");
|
||||
writeWatchName();
|
||||
requestBleConfiguration();
|
||||
writeAppInformation();
|
||||
// The rest of the init sequence is not strictly needed; we keep
|
||||
// it here for future reference.
|
||||
//requestBleConfiguration();
|
||||
} else if(data[0] == CasioConstants.characteristicToByte.get("CASIO_BLE_FEATURES")) {
|
||||
LOG.info("Got BLE features, requesting BLE settings");
|
||||
requestBleSettings();
|
||||
@ -341,16 +352,36 @@ public class InitOperationGBX100 extends AbstractBTLEOperation<CasioGBX100Device
|
||||
LOG.info("Got DST setting, waiting...; should write DST setting and location and radio information");
|
||||
} else if(data[0] == CasioConstants.characteristicToByte.get("CASIO_SERVICE_DISCOVERY_MANAGER")) {
|
||||
if(data[1] == 0x02) {
|
||||
// The writeAllFeaturesInit request triggers bonding. However, the transaction
|
||||
// never completes. Instead, the watch sends 0x4701 notification and we abort
|
||||
// the current transaction.
|
||||
LOG.info("We need to bond here. This is actually the request for the current time.");
|
||||
writeCurrentTime();
|
||||
writeAllFeaturesInit();
|
||||
try {
|
||||
TransactionBuilder builder = createTransactionBuilder("writeCurrentTime");
|
||||
writeCurrentTime(builder);
|
||||
writeAllFeaturesInit(builder);
|
||||
support.performImmediately(builder);
|
||||
} catch(IOException e) {
|
||||
LOG.error("Error setting device to initialized: " + e.getMessage());
|
||||
}
|
||||
} else if(data[1] == 0x01) {
|
||||
LOG.info("We need to encrypt here.");
|
||||
// The writeAllFeaturesInit request triggers encryption (again). However, the transaction
|
||||
// never completes. Instead, the watch reports with 0x3d and we abort the current
|
||||
// transaction.
|
||||
getQueue().abortCurrentTransaction();
|
||||
writeAllFeaturesInit();
|
||||
}
|
||||
} else if(data[0] == 0x3d) {
|
||||
LOG.info("Init operation done.");
|
||||
support.setInitialized();
|
||||
// Finally, we set the state to initialized here!
|
||||
getQueue().abortCurrentTransaction();
|
||||
try {
|
||||
TransactionBuilder builder = createTransactionBuilder("setInitialized");
|
||||
support.setInitialized(builder);
|
||||
support.performImmediately(builder);
|
||||
} catch(IOException e) {
|
||||
LOG.error("Error setting device to initialized: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user