From 49bd90d960815a4ac192e0d7a8fe86ecc0877204 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Rebelo?= Date: Thu, 1 Jan 2026 16:21:58 +0000 Subject: [PATCH] Liveview: Switch to BTBR support class --- .../devices/liveview/LiveviewIoThread.java | 99 ------------------- .../devices/liveview/LiveviewSupport.java | 90 ++++++++++++++--- 2 files changed, 78 insertions(+), 111 deletions(-) delete mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/liveview/LiveviewIoThread.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/liveview/LiveviewIoThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/liveview/LiveviewIoThread.java deleted file mode 100644 index 2d50a45fa4..0000000000 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/liveview/LiveviewIoThread.java +++ /dev/null @@ -1,99 +0,0 @@ -/* Copyright (C) 2016-2024 Carsten Pfeiffer, Daniele Gobbetti - - 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 . */ -package nodomain.freeyourgadget.gadgetbridge.service.devices.liveview; - -import android.bluetooth.BluetoothAdapter; -import android.content.Context; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; -import java.util.UUID; - -import nodomain.freeyourgadget.gadgetbridge.devices.liveview.LiveviewConstants; -import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; -import nodomain.freeyourgadget.gadgetbridge.service.btclassic.BtClassicIoThread; -import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol; -import nodomain.freeyourgadget.gadgetbridge.util.GB; - -public class LiveviewIoThread extends BtClassicIoThread { - private static final Logger LOG = LoggerFactory.getLogger(LiveviewIoThread.class); - - private static final UUID SERIAL = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); - - public LiveviewIoThread(GBDevice gbDevice, Context context, GBDeviceProtocol lvProtocol, LiveviewSupport lvSupport, BluetoothAdapter lvBtAdapter) { - super(gbDevice, context, lvProtocol, lvSupport, lvBtAdapter); - } - - @Override - protected byte[] parseIncoming(InputStream inputStream) throws IOException { - ByteArrayOutputStream msgStream = new ByteArrayOutputStream(); - - boolean finished = false; - ReaderState state = ReaderState.ID; - byte[] incoming = new byte[1]; - - while (!finished) { - inputStream.read(incoming); - msgStream.write(incoming); - - switch (state) { - case ID: - state = ReaderState.HEADER_LEN; - incoming = new byte[1]; - break; - case HEADER_LEN: - int headerSize = 0xff & incoming[0]; - state = ReaderState.HEADER; - incoming = new byte[headerSize]; - break; - case HEADER: - int payloadSize = getLastInt(msgStream); - if (payloadSize < 0 || payloadSize > 8000) //this will possibly be changed in the future - throw new IOException(); - state = ReaderState.PAYLOAD; - incoming = new byte[payloadSize]; - break; - case PAYLOAD: //read is blocking, if we are here we have all the data - finished = true; - break; - } - } - byte[] msgArray = msgStream.toByteArray(); - LOG.debug("received: " + GB.hexdump(msgArray, 0, msgArray.length)); - return msgArray; - } - - - /** - * Enumeration containing the possible internal status of the reader. - */ - private enum ReaderState { - ID, HEADER_LEN, HEADER, PAYLOAD; - } - - private int getLastInt(ByteArrayOutputStream stream) { - byte[] array = stream.toByteArray(); - ByteBuffer buffer = ByteBuffer.wrap(array, array.length - 4, 4); - buffer.order(LiveviewConstants.BYTE_ORDER); - return buffer.getInt(); - } -} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/liveview/LiveviewSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/liveview/LiveviewSupport.java index e44818fcf6..1c7da25a6e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/liveview/LiveviewSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/liveview/LiveviewSupport.java @@ -17,28 +17,94 @@ along with this program. If not, see . */ package nodomain.freeyourgadget.gadgetbridge.service.devices.liveview; -import nodomain.freeyourgadget.gadgetbridge.service.serial.AbstractSerialDeviceSupport; -import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceIoThread; -import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.ByteBuffer; +import java.util.UUID; + +import nodomain.freeyourgadget.gadgetbridge.devices.liveview.LiveviewConstants; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.service.btbr.TransactionBuilder; +import nodomain.freeyourgadget.gadgetbridge.service.serial.AbstractSerialDeviceSupportV2; + +public class LiveviewSupport extends AbstractSerialDeviceSupportV2 { + private static final Logger LOG = LoggerFactory.getLogger(LiveviewSupport.class); + + private final ByteBuffer packetBuffer = ByteBuffer.allocate(8000).order(LiveviewConstants.BYTE_ORDER); + + public LiveviewSupport() { + super(8000); + addSupportedService(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")); + } -public class LiveviewSupport extends AbstractSerialDeviceSupport { @Override - protected GBDeviceProtocol createDeviceProtocol() { + protected LiveviewProtocol createDeviceProtocol() { return new LiveviewProtocol(getDevice()); } @Override - protected GBDeviceIoThread createDeviceIOThread() { - return new LiveviewIoThread(getDevice(), getContext(), getDeviceProtocol(), LiveviewSupport.this, getBluetoothAdapter()); + protected TransactionBuilder initializeDevice(final TransactionBuilder builder) { + packetBuffer.clear(); + builder.write(mDeviceProtocol.encodeSetTime()); + builder.setDeviceState(GBDevice.State.INITIALIZED); + return builder; } @Override - public boolean useAutoConnect() { - return false; + public void onSocketRead(final byte[] data) { + packetBuffer.put(data); + packetBuffer.flip(); + + while (packetBuffer.hasRemaining()) { + final int start = packetBuffer.position(); + packetBuffer.mark(); + + if (packetBuffer.remaining() < 2) { + // not enough bytes for min packet + packetBuffer.reset(); + break; + } + + packetBuffer.get(); // id + + final int headerLength = packetBuffer.get() & 0xff; + if (packetBuffer.remaining() < headerLength) { + // not enough bytes + packetBuffer.reset(); + break; + } + + final byte[] header = new byte[headerLength]; + packetBuffer.get(header); + + final int payloadSize = getLastInt(header); + if (packetBuffer.remaining() < payloadSize) { + // not enough bytes + packetBuffer.reset(); + break; + } + + final int end = packetBuffer.position() + payloadSize; + + final byte[] packet = new byte[end - start]; + packetBuffer.position(start); + packetBuffer.get(packet); + + // Handle it upstream, to the protocol + try { + super.onSocketRead(packet); + } catch (final Exception e) { + LOG.error("Failed to handle command", e); + } + } + + packetBuffer.compact(); } - @Override - public synchronized LiveviewIoThread getDeviceIOThread() { - return (LiveviewIoThread) super.getDeviceIOThread(); + private int getLastInt(final byte[] array) { + final ByteBuffer buffer = ByteBuffer.wrap(array, array.length - 4, 4); + buffer.order(LiveviewConstants.BYTE_ORDER); + return buffer.getInt(); } }