mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-08-26 09:11:37 +02:00
added call notification support (doesnt work on all phones)
This commit is contained in:
parent
17ade7e591
commit
f9a4c1ad35
@ -1,18 +1,33 @@
|
|||||||
package nodomain.freeyourgadget.gadgetbridge.devices.qhybrid;
|
package nodomain.freeyourgadget.gadgetbridge.devices.qhybrid;
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.PlayNotificationRequest;
|
import java.nio.ByteOrder;
|
||||||
|
import java.util.zip.CRC32;
|
||||||
|
|
||||||
public class NotificationHRConfiguration implements Serializable {
|
public class NotificationHRConfiguration implements Serializable {
|
||||||
private String packageName;
|
private String packageName;
|
||||||
private long id = -1;
|
private long id = -1;
|
||||||
|
private byte[] packageCrc;
|
||||||
|
|
||||||
public NotificationHRConfiguration(String packageName, long id) {
|
public NotificationHRConfiguration(String packageName, long id) {
|
||||||
this.packageName = packageName;
|
this.packageName = packageName;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
|
||||||
|
CRC32 crc = new CRC32();
|
||||||
|
crc.update(packageName.getBytes());
|
||||||
|
|
||||||
|
this.packageCrc = ByteBuffer
|
||||||
|
.allocate(4)
|
||||||
|
.order(ByteOrder.LITTLE_ENDIAN)
|
||||||
|
.putInt((int) crc.getValue())
|
||||||
|
.array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotificationHRConfiguration(String packageName, byte[] packageCrc, long id) {
|
||||||
|
this.id = id;
|
||||||
|
this.packageCrc = packageCrc;
|
||||||
|
this.packageName = packageName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPackageName() {
|
public String getPackageName() {
|
||||||
@ -22,4 +37,8 @@ public class NotificationHRConfiguration implements Serializable {
|
|||||||
public long getId() {
|
public long getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] getPackageCrc() {
|
||||||
|
return packageCrc;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ import java.util.Iterator;
|
|||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCallControl;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventFindPhone;
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventFindPhone;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl;
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.HRConfigActivity;
|
import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.HRConfigActivity;
|
||||||
@ -37,9 +38,11 @@ import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil.FossilWatchAdapter;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil.FossilWatchAdapter;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.FossilRequest;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.RequestMtuRequest;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.RequestMtuRequest;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.SetDeviceStateRequest;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.SetDeviceStateRequest;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.configuration.ConfigurationPutRequest.TimeConfigItem;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.configuration.ConfigurationPutRequest.TimeConfigItem;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.file.FilePutRequest;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.notification.PlayCallNotificationRequest;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.notification.PlayCallNotificationRequest;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.notification.PlayNotificationRequest;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.notification.PlayNotificationRequest;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.notification.PlayTextNotificationRequest;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.notification.PlayTextNotificationRequest;
|
||||||
@ -99,46 +102,8 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
|
|||||||
|
|
||||||
queueWrite(new SetDeviceStateRequest(GBDevice.State.INITIALIZING));
|
queueWrite(new SetDeviceStateRequest(GBDevice.State.INITIALIZING));
|
||||||
|
|
||||||
// icons
|
|
||||||
|
|
||||||
loadNotificationConfigurations();
|
loadNotificationConfigurations();
|
||||||
queueWrite(new NotificationFilterPutHRRequest(this.notificationConfigurations, this));
|
queueWrite(new NotificationFilterPutHRRequest(this.notificationConfigurations, this));
|
||||||
// queueWrite(new NotificationFilterPutHRRequest(this.notificationConfigurations,this));
|
|
||||||
|
|
||||||
/*try {
|
|
||||||
final String[] appNames = {"instagram", "snapchat", "line", "whatsapp"};
|
|
||||||
final String[] paths = {
|
|
||||||
"/storage/emulated/0/Q/images/icInstagram.icon",
|
|
||||||
"/storage/emulated/0/Q/images/icSnapchat.icon",
|
|
||||||
"/storage/emulated/0/Q/images/icLine.icon",
|
|
||||||
"/storage/emulated/0/Q/images/icWhatsapp.icon"
|
|
||||||
};
|
|
||||||
|
|
||||||
NotificationHRConfiguration[] configs = new NotificationHRConfiguration[4];
|
|
||||||
NotificationImage[] images = new NotificationImage[4];
|
|
||||||
for(int i = 0; i < 4; i++){
|
|
||||||
FileInputStream fis = new FileInputStream(paths[i]);
|
|
||||||
byte[] imageData = new byte[fis.available()];
|
|
||||||
fis.read(imageData);
|
|
||||||
fis.close();
|
|
||||||
configs[i] = new NotificationHRConfiguration(appNames[i], i);
|
|
||||||
images[i] = new NotificationImage(appNames[i], imageData);
|
|
||||||
}
|
|
||||||
queueWrite(new NotificationImagePutRequest(images, this));
|
|
||||||
queueWrite(new NotificationFilterPutHRRequest(configs, this));
|
|
||||||
|
|
||||||
for(String appName : appNames){
|
|
||||||
queueWrite(new PlayNotificationHRRequest(
|
|
||||||
appName,
|
|
||||||
appName.toUpperCase(),
|
|
||||||
"this is some strange message",
|
|
||||||
this
|
|
||||||
));
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}*/
|
|
||||||
|
|
||||||
setVibrationStrength((short) 75);
|
setVibrationStrength((short) 75);
|
||||||
|
|
||||||
syncSettings();
|
syncSettings();
|
||||||
@ -165,6 +130,7 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
|
|||||||
private void loadNotificationConfigurations(){
|
private void loadNotificationConfigurations(){
|
||||||
this.notificationConfigurations = new NotificationHRConfiguration[]{
|
this.notificationConfigurations = new NotificationHRConfiguration[]{
|
||||||
new NotificationHRConfiguration("generic", 0),
|
new NotificationHRConfiguration("generic", 0),
|
||||||
|
new NotificationHRConfiguration("call", new byte[]{(byte)0x80, (byte) 0x00, (byte) 0x59, (byte) 0xB7}, 0)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -539,7 +505,9 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
|
|||||||
|
|
||||||
byte requestType = value[1];
|
byte requestType = value[1];
|
||||||
|
|
||||||
if (requestType == (byte) 0x05) {
|
if(requestType == (byte) 0x04){
|
||||||
|
handleCallRequest(value);
|
||||||
|
}else if (requestType == (byte) 0x05) {
|
||||||
handleMusicRequest(value);
|
handleMusicRequest(value);
|
||||||
} else if (requestType == (byte) 0x01) {
|
} else if (requestType == (byte) 0x01) {
|
||||||
int eventId = value[2];
|
int eventId = value[2];
|
||||||
@ -608,6 +576,16 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleCallRequest(byte[] value) {
|
||||||
|
boolean acceptCall = value[7] == (byte) 0x00;
|
||||||
|
queueWrite(new PlayCallNotificationRequest("", false, this));
|
||||||
|
|
||||||
|
GBDeviceEventCallControl callControlEvent = new GBDeviceEventCallControl();
|
||||||
|
callControlEvent.event = acceptCall ? GBDeviceEventCallControl.Event.START : GBDeviceEventCallControl.Event.REJECT;
|
||||||
|
|
||||||
|
getDeviceSupport().evaluateGBDeviceEvent(callControlEvent);
|
||||||
|
}
|
||||||
|
|
||||||
private void handleMusicRequest(byte[] value) {
|
private void handleMusicRequest(byte[] value) {
|
||||||
byte command = value[3];
|
byte command = value[3];
|
||||||
logger.info("got music command: " + command);
|
logger.info("got music command: " + command);
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.notification;
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.notification;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil.FossilWatchAdapter;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil.FossilWatchAdapter;
|
||||||
|
|
||||||
public class PlayCallNotificationRequest extends PlayNotificationRequest {
|
public class PlayCallNotificationRequest extends PlayNotificationRequest {
|
||||||
public PlayCallNotificationRequest(String number, boolean callStart, FossilWatchAdapter adapter) {
|
public PlayCallNotificationRequest(String number, boolean callStart, FossilWatchAdapter adapter) {
|
||||||
super(callStart ? 1 : 7, callStart ? 8 : 2, "generic", number, "Incoming Call", adapter);
|
super(callStart ? 1 : 7, callStart ? 8 : 2,
|
||||||
|
ByteBuffer.wrap(new byte[]{(byte) 0x80, (byte) 0x00, (byte) 0x59, (byte) 0xB7}).order(ByteOrder.LITTLE_ENDIAN).getInt(),
|
||||||
|
number, "Incoming Call", adapter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,8 +26,6 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fos
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
||||||
|
|
||||||
public abstract class PlayNotificationRequest extends FilePutRequest {
|
public abstract class PlayNotificationRequest extends FilePutRequest {
|
||||||
static int id = 0;
|
|
||||||
|
|
||||||
public PlayNotificationRequest(int notificationType, int flags, String packageName, FossilWatchAdapter adapter) {
|
public PlayNotificationRequest(int notificationType, int flags, String packageName, FossilWatchAdapter adapter) {
|
||||||
super((short) 0x0900, createFile(notificationType, flags, packageName, packageName, packageName), adapter);
|
super((short) 0x0900, createFile(notificationType, flags, packageName, packageName, packageName), adapter);
|
||||||
}
|
}
|
||||||
@ -36,6 +34,9 @@ public abstract class PlayNotificationRequest extends FilePutRequest {
|
|||||||
super((short) 0x0900, createFile(notificationType, flags, packageName, sender, message), adapter);
|
super((short) 0x0900, createFile(notificationType, flags, packageName, sender, message), adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PlayNotificationRequest(int notificationType, int flags, int packageCRC, String sender, String message, FossilWatchAdapter adapter) {
|
||||||
|
super((short) 0x0900, createFile(notificationType, flags, "whatever", sender, message, packageCRC), adapter);
|
||||||
|
}
|
||||||
|
|
||||||
private static byte[] createFile(int notificationType, int flags, String packageName, String sender, String message){
|
private static byte[] createFile(int notificationType, int flags, String packageName, String sender, String message){
|
||||||
CRC32 crc = new CRC32();
|
CRC32 crc = new CRC32();
|
||||||
@ -73,7 +74,7 @@ public abstract class PlayNotificationRequest extends FilePutRequest {
|
|||||||
mainBuffer.put((byte) senderBytes.length);
|
mainBuffer.put((byte) senderBytes.length);
|
||||||
mainBuffer.put((byte) messageBytes.length);
|
mainBuffer.put((byte) messageBytes.length);
|
||||||
|
|
||||||
mainBuffer.putInt(id++); // messageId
|
mainBuffer.putInt(0); // messageId
|
||||||
mainBuffer.putInt(packageCrc);
|
mainBuffer.putInt(packageCrc);
|
||||||
mainBuffer.put(titleBytes);
|
mainBuffer.put(titleBytes);
|
||||||
mainBuffer.put(senderBytes);
|
mainBuffer.put(senderBytes);
|
||||||
|
@ -3,7 +3,6 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fo
|
|||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.zip.CRC32;
|
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.NotificationHRConfiguration;
|
import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.NotificationHRConfiguration;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil.FossilWatchAdapter;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil.FossilWatchAdapter;
|
||||||
@ -21,20 +20,16 @@ public class NotificationFilterPutHRRequest extends FilePutRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] createFile(NotificationHRConfiguration[] configs) {
|
private static byte[] createFile(NotificationHRConfiguration[] configs) {
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(configs.length * 28);
|
int payloadLength = configs.length * 28;
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(payloadLength);
|
||||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
|
||||||
for (NotificationHRConfiguration config : configs) {
|
for (NotificationHRConfiguration config : configs) {
|
||||||
buffer.putShort((short) 28); //packet length
|
payloadLength = 26;
|
||||||
|
|
||||||
CRC32 crc = new CRC32();
|
buffer.putShort((short) payloadLength); //packet length
|
||||||
crc.update(config.getPackageName().getBytes());
|
|
||||||
|
|
||||||
byte[] crcBytes = ByteBuffer
|
byte[] crcBytes = config.getPackageCrc();
|
||||||
.allocate(4)
|
|
||||||
.order(ByteOrder.LITTLE_ENDIAN)
|
|
||||||
.putInt((int) crc.getValue())
|
|
||||||
.array();
|
|
||||||
|
|
||||||
// 6 bytes
|
// 6 bytes
|
||||||
buffer.put(PacketID.PACKAGE_NAME_CRC.id)
|
buffer.put(PacketID.PACKAGE_NAME_CRC.id)
|
||||||
@ -44,7 +39,7 @@ public class NotificationFilterPutHRRequest extends FilePutRequest {
|
|||||||
// 3 bytes
|
// 3 bytes
|
||||||
buffer.put(PacketID.GROUP_ID.id)
|
buffer.put(PacketID.GROUP_ID.id)
|
||||||
.put((byte) 1)
|
.put((byte) 1)
|
||||||
.put((byte) 2);
|
.put((byte) 0);
|
||||||
|
|
||||||
// 3 bytes
|
// 3 bytes
|
||||||
buffer.put(PacketID.PRIORITY.id)
|
buffer.put(PacketID.PRIORITY.id)
|
||||||
|
@ -53,7 +53,7 @@ public class GBCallControlReceiver extends BroadcastReceiver {
|
|||||||
telephonyService.answerRingingCall();
|
telephonyService.answerRingingCall();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.warn("could not start or hangup call");
|
LOG.warn("could not start or hangup call", e);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
Loading…
Reference in New Issue
Block a user