mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2025-06-05 21:49:48 +02:00
Lefun: Implement notification support
This commit is contained in:
@@ -36,6 +36,8 @@ public class NotificationCommand extends BaseCommand {
|
|||||||
public static final byte EXTENDED_SERVICE_TYPE_LINE = 5;
|
public static final byte EXTENDED_SERVICE_TYPE_LINE = 5;
|
||||||
public static final byte EXTENDED_SERVICE_TYPE_KAKAOTALK = 6;
|
public static final byte EXTENDED_SERVICE_TYPE_KAKAOTALK = 6;
|
||||||
|
|
||||||
|
public static final int MAX_PAYLOAD_LENGTH = 13;
|
||||||
|
|
||||||
private byte serviceType;
|
private byte serviceType;
|
||||||
private byte totalPieces;
|
private byte totalPieces;
|
||||||
private byte currentPiece;
|
private byte currentPiece;
|
||||||
@@ -104,7 +106,8 @@ public class NotificationCommand extends BaseCommand {
|
|||||||
protected byte serializeParams(ByteBuffer params) {
|
protected byte serializeParams(ByteBuffer params) {
|
||||||
boolean hasExtendedServiceType = (serviceType & (1 << SERVICE_TYPE_EXTENDED)) != 0
|
boolean hasExtendedServiceType = (serviceType & (1 << SERVICE_TYPE_EXTENDED)) != 0
|
||||||
&& (extendedServiceType & 0x0f) != 0;
|
&& (extendedServiceType & 0x0f) != 0;
|
||||||
int maxPayloadLength = hasExtendedServiceType ? 12 : 13;
|
int maxPayloadLength = MAX_PAYLOAD_LENGTH;
|
||||||
|
if (hasExtendedServiceType) maxPayloadLength -= 1;
|
||||||
|
|
||||||
if (payload.length > maxPayloadLength)
|
if (payload.length > maxPayloadLength)
|
||||||
throw new IllegalStateException("Payload is too long");
|
throw new IllegalStateException("Payload is too long");
|
||||||
|
@@ -71,6 +71,9 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.lefun.requests.GetFi
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.lefun.requests.GetPpgDataRequest;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.lefun.requests.GetPpgDataRequest;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.lefun.requests.GetSleepDataRequest;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.lefun.requests.GetSleepDataRequest;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.lefun.requests.Request;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.lefun.requests.Request;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.lefun.requests.AbstractSendNotificationRequest;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.lefun.requests.SendCallNotificationRequest;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.lefun.requests.SendNotificationRequest;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.lefun.requests.SetAlarmRequest;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.lefun.requests.SetAlarmRequest;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.lefun.requests.SetTimeRequest;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.lefun.requests.SetTimeRequest;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.lefun.requests.StartPpgRequest;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.lefun.requests.StartPpgRequest;
|
||||||
@@ -126,7 +129,16 @@ public class LefunDeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNotification(NotificationSpec notificationSpec) {
|
public void onNotification(NotificationSpec notificationSpec) {
|
||||||
|
try {
|
||||||
|
TransactionBuilder builder = performInitialized(SetTimeRequest.class.getSimpleName());
|
||||||
|
SendNotificationRequest request = new SendNotificationRequest(this, builder);
|
||||||
|
request.setNotification(notificationSpec);
|
||||||
|
request.perform();
|
||||||
|
performConnected(builder.getTransaction());
|
||||||
|
} catch (IOException e) {
|
||||||
|
GB.toast(getContext(), "Failed to send notification", Toast.LENGTH_SHORT,
|
||||||
|
GB.ERROR, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -173,7 +185,20 @@ public class LefunDeviceSupport extends AbstractBTLEDeviceSupport {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSetCallState(CallSpec callSpec) {
|
public void onSetCallState(CallSpec callSpec) {
|
||||||
|
switch (callSpec.command) {
|
||||||
|
case CallSpec.CALL_INCOMING:
|
||||||
|
try {
|
||||||
|
TransactionBuilder builder = performInitialized(SetTimeRequest.class.getSimpleName());
|
||||||
|
SendCallNotificationRequest request = new SendCallNotificationRequest(this, builder);
|
||||||
|
request.setCallNotification(callSpec);
|
||||||
|
request.perform();
|
||||||
|
performConnected(builder.getTransaction());
|
||||||
|
} catch (IOException e) {
|
||||||
|
GB.toast(getContext(), "Failed to send call notification", Toast.LENGTH_SHORT,
|
||||||
|
GB.ERROR, e);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -0,0 +1,98 @@
|
|||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.lefun.requests;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothGattCharacteristic;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.LefunConstants;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands.NotificationCommand;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.lefun.LefunDeviceSupport;
|
||||||
|
|
||||||
|
public abstract class AbstractSendNotificationRequest extends Request {
|
||||||
|
protected AbstractSendNotificationRequest(LefunDeviceSupport support, TransactionBuilder builder) {
|
||||||
|
super(support, builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract String getMessage();
|
||||||
|
|
||||||
|
protected abstract byte getNotificationType();
|
||||||
|
|
||||||
|
protected abstract byte getExtendedNotificationType();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] createRequest() {
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doPerform() throws IOException {
|
||||||
|
byte notificationType = getNotificationType();
|
||||||
|
byte extendedNotificationType = getExtendedNotificationType();
|
||||||
|
boolean reserveSpaceForExtended = notificationType == NotificationCommand.SERVICE_TYPE_EXTENDED;
|
||||||
|
byte[] encoded = getMessage().getBytes(StandardCharsets.UTF_8);
|
||||||
|
ByteBuffer buffer = ByteBuffer.wrap(encoded);
|
||||||
|
|
||||||
|
BluetoothGattCharacteristic characteristic = getSupport()
|
||||||
|
.getCharacteristic(LefunConstants.UUID_CHARACTERISTIC_LEFUN_WRITE);
|
||||||
|
|
||||||
|
List<NotificationCommand> commandList = new ArrayList<>();
|
||||||
|
for (int i = 0; i < 0xff; ++i) {
|
||||||
|
NotificationCommand cmd = new NotificationCommand();
|
||||||
|
cmd.setServiceType(notificationType);
|
||||||
|
cmd.setExtendedServiceType(extendedNotificationType);
|
||||||
|
cmd.setCurrentPiece((byte) (i + 1));
|
||||||
|
|
||||||
|
int maxPayloadLength = NotificationCommand.MAX_PAYLOAD_LENGTH;
|
||||||
|
if (reserveSpaceForExtended) maxPayloadLength -= 1;
|
||||||
|
maxPayloadLength = Math.min(maxPayloadLength, buffer.limit() - buffer.position());
|
||||||
|
if (maxPayloadLength == 0) break;
|
||||||
|
|
||||||
|
byte[] payload = new byte[maxPayloadLength];
|
||||||
|
buffer.get(payload);
|
||||||
|
cmd.setPayload(payload);
|
||||||
|
|
||||||
|
commandList.add(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (NotificationCommand cmd : commandList) {
|
||||||
|
cmd.setTotalPieces((byte) commandList.size());
|
||||||
|
builder.write(characteristic, cmd.serialize());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSelfQueue())
|
||||||
|
getSupport().performConnected(builder.getTransaction());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCommandId() {
|
||||||
|
return LefunConstants.CMD_NOTIFICATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean expectsResponse() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,67 @@
|
|||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.lefun.requests;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands.NotificationCommand;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.lefun.LefunDeviceSupport;
|
||||||
|
|
||||||
|
public class SendCallNotificationRequest extends AbstractSendNotificationRequest {
|
||||||
|
public SendCallNotificationRequest(LefunDeviceSupport support, TransactionBuilder builder) {
|
||||||
|
super(support, builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CallSpec callNotification;
|
||||||
|
|
||||||
|
public CallSpec getCallNotification() {
|
||||||
|
return callNotification;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCallNotification(CallSpec callNotification) {
|
||||||
|
this.callNotification = callNotification;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getMessage() {
|
||||||
|
String message = "";
|
||||||
|
if (callNotification.number != null) {
|
||||||
|
message = callNotification.number;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callNotification.name != null) {
|
||||||
|
if (message.length() > 0) {
|
||||||
|
message += " - ";
|
||||||
|
}
|
||||||
|
message += callNotification.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte getNotificationType() {
|
||||||
|
return NotificationCommand.SERVICE_TYPE_CALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte getExtendedNotificationType() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,111 @@
|
|||||||
|
/* Copyright (C) 2016-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||||
|
Gobbetti
|
||||||
|
Copyright (C) 2020 Yukai Li
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.lefun.requests;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.lefun.commands.NotificationCommand;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.lefun.LefunDeviceSupport;
|
||||||
|
|
||||||
|
public class SendNotificationRequest extends AbstractSendNotificationRequest {
|
||||||
|
NotificationSpec notification;
|
||||||
|
|
||||||
|
public SendNotificationRequest(LefunDeviceSupport support, TransactionBuilder builder) {
|
||||||
|
super(support, builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte getNotificationType() {
|
||||||
|
switch (notification.type) {
|
||||||
|
case GENERIC_PHONE:
|
||||||
|
return NotificationCommand.SERVICE_TYPE_CALL;
|
||||||
|
case GENERIC_SMS:
|
||||||
|
case GENERIC_EMAIL:
|
||||||
|
default:
|
||||||
|
return NotificationCommand.SERVICE_TYPE_TEXT;
|
||||||
|
case WECHAT:
|
||||||
|
return NotificationCommand.SERVICE_TYPE_WECHAT;
|
||||||
|
case FACEBOOK:
|
||||||
|
case FACEBOOK_MESSENGER:
|
||||||
|
case TWITTER:
|
||||||
|
case LINKEDIN:
|
||||||
|
case WHATSAPP:
|
||||||
|
case LINE:
|
||||||
|
case KAKAO_TALK:
|
||||||
|
return NotificationCommand.SERVICE_TYPE_EXTENDED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte getExtendedNotificationType() {
|
||||||
|
switch (notification.type) {
|
||||||
|
case GENERIC_PHONE:
|
||||||
|
case GENERIC_SMS:
|
||||||
|
case GENERIC_EMAIL:
|
||||||
|
default:
|
||||||
|
case WECHAT:
|
||||||
|
return 0;
|
||||||
|
case FACEBOOK:
|
||||||
|
case FACEBOOK_MESSENGER:
|
||||||
|
return NotificationCommand.EXTENDED_SERVICE_TYPE_FACEBOOK;
|
||||||
|
case TWITTER:
|
||||||
|
return NotificationCommand.EXTENDED_SERVICE_TYPE_TWITTER;
|
||||||
|
case LINKEDIN:
|
||||||
|
return NotificationCommand.EXTENDED_SERVICE_TYPE_LINKEDIN;
|
||||||
|
case WHATSAPP:
|
||||||
|
return NotificationCommand.EXTENDED_SERVICE_TYPE_WHATSAPP;
|
||||||
|
case LINE:
|
||||||
|
return NotificationCommand.EXTENDED_SERVICE_TYPE_LINE;
|
||||||
|
case KAKAO_TALK:
|
||||||
|
return NotificationCommand.EXTENDED_SERVICE_TYPE_KAKAOTALK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotificationSpec getNotification() {
|
||||||
|
return notification;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNotification(NotificationSpec notification) {
|
||||||
|
this.notification = notification;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getMessage() {
|
||||||
|
// Based on nodomain.freeyourgadget.gadgetbridge.service.devices.id115.SendNotificationOperation
|
||||||
|
String message = "";
|
||||||
|
|
||||||
|
if (notification.phoneNumber != null) {
|
||||||
|
message += notification.phoneNumber + ": ";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notification.sender != null) {
|
||||||
|
message += notification.sender + " - ";
|
||||||
|
} else if (notification.title != null) {
|
||||||
|
message += notification.title + " - ";
|
||||||
|
} else if (notification.subject != null) {
|
||||||
|
message += notification.subject + " - ";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notification.body != null) {
|
||||||
|
message += notification.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user