From 19d68c62c6bc4c0a3c515d5b482be63bcb5f2354 Mon Sep 17 00:00:00 2001 From: dakhnod Date: Tue, 31 Dec 2019 15:25:30 +0100 Subject: [PATCH] added music info (controls WIP) --- .../devices/qhybrid/QHybridSupport.java | 16 ++++ .../devices/qhybrid/adapter/WatchAdapter.java | 8 ++ .../fossil_hr/FossilHRWatchAdapter.java | 79 ++++++++++++++++++- .../fossil_hr/music/MusicControlRequest.java | 72 +++++++++++++++++ .../fossil_hr/music/MusicInfoSetRequest.java | 41 ++++++++++ 5 files changed, 212 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/music/MusicControlRequest.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/music/MusicInfoSetRequest.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/QHybridSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/QHybridSupport.java index b73013cad..6f2d80470 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/QHybridSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/QHybridSupport.java @@ -61,6 +61,8 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; import nodomain.freeyourgadget.gadgetbridge.model.BatteryState; import nodomain.freeyourgadget.gadgetbridge.model.GenericItem; +import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; +import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.RecordedDataTypes; import nodomain.freeyourgadget.gadgetbridge.service.btle.GattCallback; @@ -314,6 +316,20 @@ public class QHybridSupport extends QHybridBaseSupport { return builder; } + @Override + public void onSetMusicInfo(MusicSpec musicSpec) { + super.onSetMusicInfo(musicSpec); + + watchAdapter.setMusicInfo(musicSpec); + } + + @Override + public void onSetMusicState(MusicStateSpec stateSpec) { + super.onSetMusicState(stateSpec); + + watchAdapter.setMusicState(stateSpec); + } + @Override public void onFetchRecordedData(int dataTypes) { if ((dataTypes & RecordedDataTypes.TYPE_ACTIVITY) != 0) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/WatchAdapter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/WatchAdapter.java index 665edb924..e967069d2 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/WatchAdapter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/WatchAdapter.java @@ -24,6 +24,8 @@ import java.util.ArrayList; import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.NotificationConfiguration; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; +import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; +import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.misfit.PlayNotificationRequest; @@ -97,4 +99,10 @@ public abstract class WatchAdapter { public void setCommuteMenuMessage(String message, boolean finished) { } + + public void setMusicInfo(MusicSpec musicSpec) { + } + + public void setMusicState(MusicStateSpec stateSpec) { + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/fossil_hr/FossilHRWatchAdapter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/fossil_hr/FossilHRWatchAdapter.java index d616fa38b..0e5e97a20 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/fossil_hr/FossilHRWatchAdapter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/adapter/fossil_hr/FossilHRWatchAdapter.java @@ -21,6 +21,8 @@ import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.HRConfigActivity; import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.NotificationHRConfiguration; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec; +import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil.FossilWatchAdapter; @@ -35,14 +37,20 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fos import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.image.Image; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.image.ImagesPutRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.menu.SetCommuteMenuMessage; +import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.music.MusicControlRequest; +import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.music.MusicInfoSetRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.notification.NotificationFilterPutHRRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.notification.NotificationImagePutRequest; +import static nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.music.MusicControlRequest.*; + public class FossilHRWatchAdapter extends FossilWatchAdapter { private byte[] secretKey = new byte[]{(byte) 0x60, (byte) 0x26, (byte) 0xB7, (byte) 0xFD, (byte) 0xB2, (byte) 0x6D, (byte) 0x05, (byte) 0x5E, (byte) 0xDA, (byte) 0xF7, (byte) 0x4B, (byte) 0x49, (byte) 0x98, (byte) 0x78, (byte) 0x02, (byte) 0x38}; private byte[] phoneRandomNumber; private byte[] watchRandomNumber; + MusicSpec currentSpec = null; + public FossilHRWatchAdapter(QHybridSupport deviceSupport) { super(deviceSupport); } @@ -93,7 +101,7 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { setTime(); - overwriteButtons(null); + // overwriteButtons(null); // negotiateSymmetricKey(); // queueWrite( @@ -103,6 +111,13 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { // ) // ); + queueWrite(new MusicInfoSetRequest( + "This is an artist", + "Some stupid album", + "What the Track!", + this + )); + queueWrite(new SetDeviceStateRequest(GBDevice.State.INITIALIZED)); } @@ -131,7 +146,33 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { ); } - private void setBackgroundImages(Image background, Image[] complications){ + @Override + public void setMusicInfo(MusicSpec musicSpec) { + if ( + currentSpec != null + && currentSpec.album.equals(musicSpec.album) + && currentSpec.artist.equals(musicSpec.artist) + && currentSpec.track.equals(musicSpec.track) + ) return; + currentSpec = musicSpec; + queueWrite(new MusicInfoSetRequest( + musicSpec.artist, + musicSpec.album, + musicSpec.track, + this + )); + } + + @Override + public void setMusicState(MusicStateSpec stateSpec) { + super.setMusicState(stateSpec); + + queueWrite(new MusicControlRequest( + stateSpec.state == MusicStateSpec.STATE_PLAYING ? MUSIC_PHONE_REQUEST.MUSIC_REQUEST_SET_PLAYING : MUSIC_PHONE_REQUEST.MUSIC_REQUEST_SET_PAUSED + )); + } + + private void setBackgroundImages(Image background, Image[] complications) { background.setAngle(0); background.setDistance(0); background.setIndexZ(0); @@ -193,7 +234,7 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { GBApplication.getPrefs().getString(HRConfigActivity.CONFIG_KEY_Q_ACTIONS, "[]") ); String[] menuItems = new String[jsonArray.length()]; - for(int i = 0; i < jsonArray.length(); i++) menuItems[i] = jsonArray.getString(i); + for (int i = 0; i < jsonArray.length(); i++) menuItems[i] = jsonArray.getString(i); queueWrite(new ButtonConfigurationPutRequest( menuItems, @@ -210,6 +251,13 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { byte[] value = characteristic.getValue(); + byte requestType = value[1]; + + if (requestType == (byte) 0x05) { + handleMusicRequest(value); + return; + } + int eventId = value[2]; try { @@ -221,7 +269,7 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { String startStop = requestJson.getJSONObject("req").getJSONObject("commuteApp._.config.commute_info") .getString("action"); - if(startStop.equals("stop")){ + if (startStop.equals("stop")) { // overwriteButtons(null); return; } @@ -236,6 +284,29 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter { } } + private void handleMusicRequest(byte[] value) { + byte command = value[3]; + + MUSIC_WATCH_REQUEST request = MUSIC_WATCH_REQUEST.fromCommandByte(command); + + MusicControlRequest r = new MusicControlRequest(MUSIC_PHONE_REQUEST.MUSIC_REQUEST_PLAY_PAUSE); + + switch (request) { + case MUSIC_REQUEST_PLAY_PAUSE: { + queueWrite(new MusicControlRequest(MUSIC_PHONE_REQUEST.MUSIC_REQUEST_PLAY_PAUSE)); + break; + } + case MUSIC_REQUEST_LOUDER: { + queueWrite(new MusicControlRequest(MUSIC_PHONE_REQUEST.MUSIC_REQUEST_LOUDER)); + break; + } + case MUSIC_REQUEST_QUITER: { + queueWrite(new MusicControlRequest(MUSIC_PHONE_REQUEST.MUSIC_REQUEST_QUITER)); + break; + } + } + } + @Override public void setCommuteMenuMessage(String message, boolean finished) { queueWrite(new SetCommuteMenuMessage(message, finished, this)); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/music/MusicControlRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/music/MusicControlRequest.java new file mode 100644 index 000000000..cc3846ef3 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/music/MusicControlRequest.java @@ -0,0 +1,72 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.music; + +import java.util.UUID; + +import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.FossilRequest; + +public class MusicControlRequest extends FossilRequest { + private MUSIC_PHONE_REQUEST request; + + public MusicControlRequest(MUSIC_PHONE_REQUEST request) { + this.request = request; + + this.data = new byte[]{ + (byte) 0x02, + (byte) 0x05, + this.request.getCommandByte(), + (byte) 0x00 + }; + } + + @Override + public boolean isFinished() { + return true; + } + + @Override + public byte[] getStartSequence() { + return null; + } + + @Override + public UUID getRequestUUID() { + return UUID.fromString("3dda0006-957f-7d4a-34a6-74696673696d"); + } + + public static enum MUSIC_WATCH_REQUEST{ + MUSIC_REQUEST_PLAY_PAUSE((byte) 0x02), + MUSIC_REQUEST_LOUDER((byte) 0x05), + MUSIC_REQUEST_QUITER((byte) 0x06), + ; + private byte commandByte; + + MUSIC_WATCH_REQUEST(byte commandByte) { + this.commandByte = commandByte; + } + + public static MUSIC_WATCH_REQUEST fromCommandByte(byte commandByte){ + for(MUSIC_WATCH_REQUEST request : MUSIC_WATCH_REQUEST.values()){ + if(request.commandByte == commandByte) return request; + } + return null; + } + } + + public static enum MUSIC_PHONE_REQUEST{ + MUSIC_REQUEST_SET_PLAYING((byte) 0x00), + MUSIC_REQUEST_SET_PAUSED((byte) 0x01), + MUSIC_REQUEST_PLAY_PAUSE((byte) 0x02), + MUSIC_REQUEST_LOUDER((byte) 0x05), + MUSIC_REQUEST_QUITER((byte) 0x06), + ; + private byte commandByte; + + public byte getCommandByte() { + return commandByte; + } + + private MUSIC_PHONE_REQUEST(byte commandByte) { + this.commandByte = commandByte; + } + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/music/MusicInfoSetRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/music/MusicInfoSetRequest.java new file mode 100644 index 000000000..f9011fc88 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qhybrid/requests/fossil_hr/music/MusicInfoSetRequest.java @@ -0,0 +1,41 @@ +package nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.music; + +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.requests.fossil.file.FilePutRequest; + +public class MusicInfoSetRequest extends FilePutRequest { + public MusicInfoSetRequest(String artist, String album, String title, FossilWatchAdapter adapter) { + super((short) 0x0400, createFile(artist, album, title), adapter); + } + + private static byte[] createFile(String artist, String album, String title){ + int length = artist.length() + album.length() + title.length() + + 3 // null terminators + + 8; // length and header + + ByteBuffer buffer = ByteBuffer.allocate(length); + buffer.order(ByteOrder.LITTLE_ENDIAN); + + buffer.putShort((short) length); + buffer.put((byte) 0x01); // dunno + buffer.put((byte) (title.length() + 1)); + buffer.put((byte) (artist.length() + 1)); + buffer.put((byte) (album.length() + 1)); + buffer.put((byte) 0x0C); // dunno + buffer.put((byte) 0x00); // dunno + + buffer.put(title.getBytes()) + .put((byte) 0x00); // null terminator + + buffer.put(artist.getBytes()) + .put((byte) 0x00); // null terminator + + buffer.put(album.getBytes()) + .put((byte) 0x00); // null terminator + + return buffer.array(); + } +}