From 0b248e83e3c050664be439d8c20fb5188874d965 Mon Sep 17 00:00:00 2001 From: Kaoru Shoji <0x0badc0de@gmail.com> Date: Mon, 30 May 2022 22:38:24 +0900 Subject: [PATCH 01/14] Fix for fixed timestamp(lsb) --- .../jp/kshoji/blemidi/util/BleMidiParser.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/BLE-MIDI-library/src/main/java/jp/kshoji/blemidi/util/BleMidiParser.java b/BLE-MIDI-library/src/main/java/jp/kshoji/blemidi/util/BleMidiParser.java index 7c3f6a9..0e15f3e 100644 --- a/BLE-MIDI-library/src/main/java/jp/kshoji/blemidi/util/BleMidiParser.java +++ b/BLE-MIDI-library/src/main/java/jp/kshoji/blemidi/util/BleMidiParser.java @@ -134,17 +134,25 @@ private long calculateEventFireTime(final int timestamp) { // checks timestamp value is always zero if (isTimestampAlwaysZero != null) { if (isTimestampAlwaysZero) { - return currentTimeMillis; + if ((timestamp & 0x7f) != 0) { + // timestamp comes with non-zero. prevent misdetection + isTimestampAlwaysZero = false; + lastTimestampRecorded = 0; + } else { + // event fires immediately + return currentTimeMillis; + } } } else { - if (timestamp == 0) { + if ((timestamp & 0x7f) == 0) { if (zeroTimestampCount >= 3) { - // decides timestamp is always zero: event fires immediately + // decides timestamp is always zero isTimestampAlwaysZero = true; - return currentTimeMillis; } else { zeroTimestampCount++; } + // event fires immediately + return currentTimeMillis; } else { isTimestampAlwaysZero = false; } From 689e503a3e7e3811a65e9ffd4488d4caf189a453 Mon Sep 17 00:00:00 2001 From: Kaoru Shoji <0x0badc0de@gmail.com> Date: Wed, 29 Jun 2022 10:53:14 +0900 Subject: [PATCH 02/14] Fix timestamp issue --- .../jp/kshoji/blemidi/util/BleMidiParser.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/BLE-MIDI-library/src/main/java/jp/kshoji/blemidi/util/BleMidiParser.java b/BLE-MIDI-library/src/main/java/jp/kshoji/blemidi/util/BleMidiParser.java index 0e15f3e..bbb0115 100644 --- a/BLE-MIDI-library/src/main/java/jp/kshoji/blemidi/util/BleMidiParser.java +++ b/BLE-MIDI-library/src/main/java/jp/kshoji/blemidi/util/BleMidiParser.java @@ -134,17 +134,26 @@ private long calculateEventFireTime(final int timestamp) { // checks timestamp value is always zero if (isTimestampAlwaysZero != null) { if (isTimestampAlwaysZero) { - if ((timestamp & 0x7f) != 0) { + if (timestamp != 0) { // timestamp comes with non-zero. prevent misdetection isTimestampAlwaysZero = false; + zeroTimestampCount = 0; lastTimestampRecorded = 0; } else { // event fires immediately return currentTimeMillis; } + } else { + if (timestamp == 0) { + // recheck timestamp value on next time + isTimestampAlwaysZero = null; + zeroTimestampCount = 0; + // event fires immediately + return currentTimeMillis; + } } } else { - if ((timestamp & 0x7f) == 0) { + if (timestamp == 0) { if (zeroTimestampCount >= 3) { // decides timestamp is always zero isTimestampAlwaysZero = true; @@ -155,6 +164,8 @@ private long calculateEventFireTime(final int timestamp) { return currentTimeMillis; } else { isTimestampAlwaysZero = false; + zeroTimestampCount = 0; + lastTimestampRecorded = 0; } } From 6e11431adfb597ea18d18c51ea5ddfa8b7b2bfcc Mon Sep 17 00:00:00 2001 From: Kaoru Shoji <0x0badc0de@gmail.com> Date: Fri, 5 Aug 2022 09:18:09 +0900 Subject: [PATCH 03/14] Create android.yml --- .github/workflows/android.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/android.yml diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml new file mode 100644 index 0000000..77dadbe --- /dev/null +++ b/.github/workflows/android.yml @@ -0,0 +1,26 @@ +name: Android CI + +on: + push: + branches: [ "develop" ] + pull_request: + branches: [ "develop" ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: set up JDK 11 + uses: actions/setup-java@v3 + with: + java-version: '11' + distribution: 'temurin' + cache: gradle + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + - name: Build with Gradle + run: ./gradlew build From f1c98227a1e912743c6ab2a51a5779a7d7d0c5cb Mon Sep 17 00:00:00 2001 From: Kaoru Shoji <0x0badc0de@gmail.com> Date: Fri, 5 Aug 2022 09:22:02 +0900 Subject: [PATCH 04/14] Add BLUETOOTH_CONNECT permission for BluetoothGatt methods --- BLE-MIDI-library/src/main/AndroidManifest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/BLE-MIDI-library/src/main/AndroidManifest.xml b/BLE-MIDI-library/src/main/AndroidManifest.xml index a56a8aa..dedaf80 100644 --- a/BLE-MIDI-library/src/main/AndroidManifest.xml +++ b/BLE-MIDI-library/src/main/AndroidManifest.xml @@ -3,6 +3,7 @@ + From 886cee0c71f15d07962691c248129fa2a8e4b3fb Mon Sep 17 00:00:00 2001 From: Kaoru Shoji <0x0badc0de@gmail.com> Date: Fri, 5 Aug 2022 09:29:12 +0900 Subject: [PATCH 05/14] Add permissions for Android 12 --- BLE-MIDI-library/src/main/AndroidManifest.xml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/BLE-MIDI-library/src/main/AndroidManifest.xml b/BLE-MIDI-library/src/main/AndroidManifest.xml index dedaf80..c0b7b6e 100644 --- a/BLE-MIDI-library/src/main/AndroidManifest.xml +++ b/BLE-MIDI-library/src/main/AndroidManifest.xml @@ -1,8 +1,11 @@ - - + + + + + From a12cfcf7a2ed419e7e4cc51005269cd8cdc9e5fc Mon Sep 17 00:00:00 2001 From: Kaoru Shoji <0x0badc0de@gmail.com> Date: Mon, 15 Aug 2022 20:34:09 +0900 Subject: [PATCH 06/14] Update Unity plugin implements --- .../kshoji/unity/midi/BleMidiUnityPlugin.java | 309 ++++++++++++------ .../OnBleMidiDeviceConnectionListener.java | 37 +++ .../midi/OnBleMidiInputEventListener.java | 157 +++++++++ .../java/com/unity3d/player/UnityPlayer.java | 2 +- 4 files changed, 412 insertions(+), 93 deletions(-) create mode 100644 BLE-MIDI-library/src/main/java/jp/kshoji/unity/midi/OnBleMidiDeviceConnectionListener.java create mode 100644 BLE-MIDI-library/src/main/java/jp/kshoji/unity/midi/OnBleMidiInputEventListener.java diff --git a/BLE-MIDI-library/src/main/java/jp/kshoji/unity/midi/BleMidiUnityPlugin.java b/BLE-MIDI-library/src/main/java/jp/kshoji/unity/midi/BleMidiUnityPlugin.java index af1876f..534e257 100644 --- a/BLE-MIDI-library/src/main/java/jp/kshoji/unity/midi/BleMidiUnityPlugin.java +++ b/BLE-MIDI-library/src/main/java/jp/kshoji/unity/midi/BleMidiUnityPlugin.java @@ -11,9 +11,6 @@ import jp.kshoji.blemidi.central.BleMidiCentralProvider; import jp.kshoji.blemidi.device.MidiInputDevice; import jp.kshoji.blemidi.device.MidiOutputDevice; -import jp.kshoji.blemidi.listener.OnMidiDeviceAttachedListener; -import jp.kshoji.blemidi.listener.OnMidiDeviceDetachedListener; -import jp.kshoji.blemidi.listener.OnMidiInputEventListener; import jp.kshoji.blemidi.peripheral.BleMidiPeripheralProvider; /** @@ -23,7 +20,7 @@ public class BleMidiUnityPlugin { private static final String GAME_OBJECT_NAME = "MidiManager"; - private final OnMidiInputEventListener midiInputEventListener = new OnMidiInputEventListener() { + private final jp.kshoji.blemidi.listener.OnMidiInputEventListener midiInputEventListener = new jp.kshoji.blemidi.listener.OnMidiInputEventListener() { private String serializeMidiMessage(String deviceAddress, int[] data) { StringBuilder sb = new StringBuilder(deviceAddress); @@ -51,119 +48,167 @@ private String serializeMidiMessage(String deviceAddress, int cable, byte[] data return sb.toString(); } - private String serializeMidiMessage(String deviceAddress, int[] data1, byte[] data2) { - StringBuilder sb = new StringBuilder(deviceAddress); - for (int i = 0; i < data1.length; i++) { - sb.append(","); - sb.append(String.format(Locale.ROOT, "%d", data1[i])); - } - for (int i = 0; i < data2.length; i++) { - sb.append(","); - sb.append(String.format(Locale.ROOT, "%d", data2[i] & 0xff)); - } - return sb.toString(); - } - - private String serializeMidiMessage(String deviceAddress, int[] data1, long data2) { - StringBuilder sb = new StringBuilder(deviceAddress); - for (int i = 0; i < data1.length; i++) { - sb.append(","); - sb.append(String.format(Locale.ROOT, "%d", data1[i])); - } - sb.append(","); - sb.append(String.format(Locale.ROOT, "%d", data2)); - return sb.toString(); - } - private static final int cable = 0; @Override - public void onMidiNoteOff(final MidiInputDevice sender, int channel, int note, int velocity) { + public void onMidiNoteOff(@NonNull final MidiInputDevice sender, int channel, int note, int velocity) { + if (onMidiInputEventListener != null) { + onMidiInputEventListener.onMidiNoteOff(sender.getDeviceAddress(), channel, note, velocity); + return; + } UnityPlayer.UnitySendMessage(GAME_OBJECT_NAME, "OnMidiNoteOff", serializeMidiMessage(sender.getDeviceAddress(), new int[] {cable, channel, note, velocity})); } @Override - public void onMidiNoteOn(final MidiInputDevice sender, int channel, int note, int velocity) { + public void onMidiNoteOn(@NonNull final MidiInputDevice sender, int channel, int note, int velocity) { + if (onMidiInputEventListener != null) { + onMidiInputEventListener.onMidiNoteOn(sender.getDeviceAddress(), channel, note, velocity); + return; + } UnityPlayer.UnitySendMessage(GAME_OBJECT_NAME, "OnMidiNoteOn", serializeMidiMessage(sender.getDeviceAddress(), new int[] {cable, channel, note, velocity})); } @Override - public void onMidiPolyphonicAftertouch(final MidiInputDevice sender, int channel, int note, int pressure) { + public void onMidiPolyphonicAftertouch(@NonNull final MidiInputDevice sender, int channel, int note, int pressure) { + if (onMidiInputEventListener != null) { + onMidiInputEventListener.onMidiPolyphonicAftertouch(sender.getDeviceAddress(), channel, note, pressure); + return; + } UnityPlayer.UnitySendMessage(GAME_OBJECT_NAME, "OnMidiPolyphonicAftertouch", serializeMidiMessage(sender.getDeviceAddress(), new int[] {cable, channel, note, pressure})); } @Override - public void onMidiControlChange(final MidiInputDevice sender, int channel, int function, int value) { + public void onMidiControlChange(@NonNull final MidiInputDevice sender, int channel, int function, int value) { + if (onMidiInputEventListener != null) { + onMidiInputEventListener.onMidiControlChange(sender.getDeviceAddress(), channel, function, value); + return; + } UnityPlayer.UnitySendMessage(GAME_OBJECT_NAME, "OnMidiControlChange", serializeMidiMessage(sender.getDeviceAddress(), new int[] {cable, channel, function, value})); } @Override - public void onMidiProgramChange(final MidiInputDevice sender, int channel, int program) { + public void onMidiProgramChange(@NonNull final MidiInputDevice sender, int channel, int program) { + if (onMidiInputEventListener != null) { + onMidiInputEventListener.onMidiProgramChange(sender.getDeviceAddress(), channel, program); + return; + } UnityPlayer.UnitySendMessage(GAME_OBJECT_NAME, "OnMidiProgramChange", serializeMidiMessage(sender.getDeviceAddress(), new int[] {cable, channel, program})); } @Override - public void onMidiChannelAftertouch(final MidiInputDevice sender, int channel, int pressure) { + public void onMidiChannelAftertouch(@NonNull final MidiInputDevice sender, int channel, int pressure) { + if (onMidiInputEventListener != null) { + onMidiInputEventListener.onMidiChannelAftertouch(sender.getDeviceAddress(), channel, pressure); + return; + } UnityPlayer.UnitySendMessage(GAME_OBJECT_NAME, "OnMidiChannelAftertouch", serializeMidiMessage(sender.getDeviceAddress(), new int[] {cable, channel, pressure})); } @Override - public void onMidiPitchWheel(final MidiInputDevice sender, int channel, int amount) { + public void onMidiPitchWheel(@NonNull final MidiInputDevice sender, int channel, int amount) { + if (onMidiInputEventListener != null) { + onMidiInputEventListener.onMidiPitchWheel(sender.getDeviceAddress(), channel, amount); + return; + } UnityPlayer.UnitySendMessage(GAME_OBJECT_NAME, "OnMidiPitchWheel", serializeMidiMessage(sender.getDeviceAddress(), new int[] {cable, channel, amount})); } @Override - public void onMidiSystemExclusive(final MidiInputDevice sender, @NonNull final byte[] systemExclusive) { + public void onMidiSystemExclusive(@NonNull final MidiInputDevice sender, @NonNull final byte[] systemExclusive) { + if (onMidiInputEventListener != null) { + onMidiInputEventListener.onMidiSystemExclusive(sender.getDeviceAddress(), systemExclusive); + return; + } UnityPlayer.UnitySendMessage(GAME_OBJECT_NAME, "OnMidiSystemExclusive", serializeMidiMessage(sender.getDeviceAddress(), cable, systemExclusive)); } @Override - public void onMidiTimeCodeQuarterFrame(MidiInputDevice sender, int timing) { + public void onMidiTimeCodeQuarterFrame(@NonNull MidiInputDevice sender, int timing) { + if (onMidiInputEventListener != null) { + onMidiInputEventListener.onMidiTimeCodeQuarterFrame(sender.getDeviceAddress(), timing); + return; + } UnityPlayer.UnitySendMessage(GAME_OBJECT_NAME, "OnMidiTimeCodeQuarterFrame", serializeMidiMessage(sender.getDeviceAddress(), new int[] {cable, timing})); } @Override - public void onMidiSongSelect(MidiInputDevice sender, int song) { + public void onMidiSongSelect(@NonNull MidiInputDevice sender, int song) { + if (onMidiInputEventListener != null) { + onMidiInputEventListener.onMidiTimeCodeQuarterFrame(sender.getDeviceAddress(), song); + return; + } UnityPlayer.UnitySendMessage(GAME_OBJECT_NAME, "OnMidiSongSelect", serializeMidiMessage(sender.getDeviceAddress(), new int[] {cable, song})); } @Override - public void onMidiSongPositionPointer(MidiInputDevice sender, int position) { + public void onMidiSongPositionPointer(@NonNull MidiInputDevice sender, int position) { + if (onMidiInputEventListener != null) { + onMidiInputEventListener.onMidiSongPositionPointer(sender.getDeviceAddress(), position); + return; + } UnityPlayer.UnitySendMessage(GAME_OBJECT_NAME, "OnMidiSongPositionPointer", serializeMidiMessage(sender.getDeviceAddress(), new int[] {cable, position})); } @Override - public void onMidiTuneRequest(MidiInputDevice sender) { + public void onMidiTuneRequest(@NonNull MidiInputDevice sender) { + if (onMidiInputEventListener != null) { + onMidiInputEventListener.onMidiTuneRequest(sender.getDeviceAddress()); + return; + } UnityPlayer.UnitySendMessage(GAME_OBJECT_NAME, "OnMidiTuneRequest", serializeMidiMessage(sender.getDeviceAddress(), new int[] {cable})); } @Override - public void onMidiTimingClock(MidiInputDevice sender) { + public void onMidiTimingClock(@NonNull MidiInputDevice sender) { + if (onMidiInputEventListener != null) { + onMidiInputEventListener.onMidiTimingClock(sender.getDeviceAddress()); + return; + } UnityPlayer.UnitySendMessage(GAME_OBJECT_NAME, "OnMidiTimingClock", serializeMidiMessage(sender.getDeviceAddress(), new int[] {cable})); } @Override - public void onMidiStart(MidiInputDevice sender) { + public void onMidiStart(@NonNull MidiInputDevice sender) { + if (onMidiInputEventListener != null) { + onMidiInputEventListener.onMidiStart(sender.getDeviceAddress()); + return; + } UnityPlayer.UnitySendMessage(GAME_OBJECT_NAME, "OnMidiStart", serializeMidiMessage(sender.getDeviceAddress(), new int[] {cable})); } @Override - public void onMidiContinue(MidiInputDevice sender) { + public void onMidiContinue(@NonNull MidiInputDevice sender) { + if (onMidiInputEventListener != null) { + onMidiInputEventListener.onMidiContinue(sender.getDeviceAddress()); + return; + } UnityPlayer.UnitySendMessage(GAME_OBJECT_NAME, "OnMidiContinue", serializeMidiMessage(sender.getDeviceAddress(), new int[] {cable})); } @Override - public void onMidiStop(MidiInputDevice sender) { + public void onMidiStop(@NonNull MidiInputDevice sender) { + if (onMidiInputEventListener != null) { + onMidiInputEventListener.onMidiStop(sender.getDeviceAddress()); + return; + } UnityPlayer.UnitySendMessage(GAME_OBJECT_NAME, "OnMidiStop", serializeMidiMessage(sender.getDeviceAddress(), new int[] {cable})); } @Override - public void onMidiActiveSensing(MidiInputDevice sender) { + public void onMidiActiveSensing(@NonNull MidiInputDevice sender) { + if (onMidiInputEventListener != null) { + onMidiInputEventListener.onMidiActiveSensing(sender.getDeviceAddress()); + return; + } UnityPlayer.UnitySendMessage(GAME_OBJECT_NAME, "OnMidiActiveSensing", serializeMidiMessage(sender.getDeviceAddress(), new int[] {cable})); } @Override - public void onMidiReset(MidiInputDevice sender) { + public void onMidiReset(@NonNull MidiInputDevice sender) { + if (onMidiInputEventListener != null) { + onMidiInputEventListener.onMidiReset(sender.getDeviceAddress()); + return; + } UnityPlayer.UnitySendMessage(GAME_OBJECT_NAME, "OnMidiReset", serializeMidiMessage(sender.getDeviceAddress(), new int[] {cable})); } @@ -188,6 +233,12 @@ public void sendMidiNoteOn(String serializedMidiMessage) { midiOutputDevice.sendMidiNoteOn(Integer.parseInt(split[2]), Integer.parseInt(split[3]), Integer.parseInt(split[4])); } } + public void sendMidiNoteOn(String deviceId, int channel, int note, int velocity) { + MidiOutputDevice midiOutputDevice = midiOutputDeviceMap.get(deviceId); + if (midiOutputDevice != null) { + midiOutputDevice.sendMidiNoteOn(channel, note, velocity); + } + } public void sendMidiNoteOff(String serializedMidiMessage) { String[] split = serializedMidiMessage.split(","); @@ -199,6 +250,12 @@ public void sendMidiNoteOff(String serializedMidiMessage) { midiOutputDevice.sendMidiNoteOff(Integer.parseInt(split[2]), Integer.parseInt(split[3]), Integer.parseInt(split[4])); } } + public void sendMidiNoteOff(String deviceId, int channel, int note, int velocity) { + MidiOutputDevice midiOutputDevice = midiOutputDeviceMap.get(deviceId); + if (midiOutputDevice != null) { + midiOutputDevice.sendMidiNoteOff(channel, note, velocity); + } + } public void sendMidiPolyphonicAftertouch(String serializedMidiMessage) { String[] split = serializedMidiMessage.split(","); @@ -210,6 +267,12 @@ public void sendMidiPolyphonicAftertouch(String serializedMidiMessage) { midiOutputDevice.sendMidiPolyphonicAftertouch(Integer.parseInt(split[2]), Integer.parseInt(split[3]), Integer.parseInt(split[4])); } } + public void sendMidiPolyphonicAftertouch(String deviceId, int channel, int note, int pressure) { + MidiOutputDevice midiOutputDevice = midiOutputDeviceMap.get(deviceId); + if (midiOutputDevice != null) { + midiOutputDevice.sendMidiPolyphonicAftertouch(channel, note, pressure); + } + } public void sendMidiControlChange(String serializedMidiMessage) { String[] split = serializedMidiMessage.split(","); @@ -221,6 +284,12 @@ public void sendMidiControlChange(String serializedMidiMessage) { midiOutputDevice.sendMidiControlChange(Integer.parseInt(split[2]), Integer.parseInt(split[3]), Integer.parseInt(split[4])); } } + public void sendMidiControlChange(String deviceId, int channel, int function, int value) { + MidiOutputDevice midiOutputDevice = midiOutputDeviceMap.get(deviceId); + if (midiOutputDevice != null) { + midiOutputDevice.sendMidiControlChange(channel, function, value); + } + } public void sendMidiProgramChange(String serializedMidiMessage) { String[] split = serializedMidiMessage.split(","); @@ -232,6 +301,12 @@ public void sendMidiProgramChange(String serializedMidiMessage) { midiOutputDevice.sendMidiProgramChange(Integer.parseInt(split[2]), Integer.parseInt(split[3])); } } + public void sendMidiProgramChange(String deviceId, int channel, int program) { + MidiOutputDevice midiOutputDevice = midiOutputDeviceMap.get(deviceId); + if (midiOutputDevice != null) { + midiOutputDevice.sendMidiProgramChange(channel, program); + } + } public void sendMidiChannelAftertouch(String serializedMidiMessage) { String[] split = serializedMidiMessage.split(","); @@ -243,6 +318,12 @@ public void sendMidiChannelAftertouch(String serializedMidiMessage) { midiOutputDevice.sendMidiChannelAftertouch(Integer.parseInt(split[2]), Integer.parseInt(split[3])); } } + public void sendMidiChannelAftertouch(String deviceId, int channel, int pressure) { + MidiOutputDevice midiOutputDevice = midiOutputDeviceMap.get(deviceId); + if (midiOutputDevice != null) { + midiOutputDevice.sendMidiChannelAftertouch(channel, pressure); + } + } public void sendMidiPitchWheel(String serializedMidiMessage) { String[] split = serializedMidiMessage.split(","); @@ -254,6 +335,12 @@ public void sendMidiPitchWheel(String serializedMidiMessage) { midiOutputDevice.sendMidiPitchWheel(Integer.parseInt(split[2]), Integer.parseInt(split[3])); } } + public void sendMidiPitchWheel(String deviceId, int channel, int amount) { + MidiOutputDevice midiOutputDevice = midiOutputDeviceMap.get(deviceId); + if (midiOutputDevice != null) { + midiOutputDevice.sendMidiPitchWheel(channel, amount); + } + } public void sendMidiSystemExclusive(String serializedMidiMessage) { String[] split = serializedMidiMessage.split(","); @@ -269,6 +356,12 @@ public void sendMidiSystemExclusive(String serializedMidiMessage) { midiOutputDevice.sendMidiSystemExclusive(sysEx); } } + public void sendMidiSystemExclusive(String deviceId, byte[] systemExclusive) { + MidiOutputDevice midiOutputDevice = midiOutputDeviceMap.get(deviceId); + if (midiOutputDevice != null) { + midiOutputDevice.sendMidiSystemExclusive(systemExclusive); + } + } public void sendMidiTimeCodeQuarterFrame(String serializedMidiMessage) { String[] split = serializedMidiMessage.split(","); @@ -280,6 +373,12 @@ public void sendMidiTimeCodeQuarterFrame(String serializedMidiMessage) { midiOutputDevice.sendMidiTimeCodeQuarterFrame(Integer.parseInt(split[2])); } } + public void sendMidiTimeCodeQuarterFrame(String deviceId, int timing) { + MidiOutputDevice midiOutputDevice = midiOutputDeviceMap.get(deviceId); + if (midiOutputDevice != null) { + midiOutputDevice.sendMidiTimeCodeQuarterFrame(timing); + } + } public void sendMidiSongSelect(String serializedMidiMessage) { String[] split = serializedMidiMessage.split(","); @@ -291,6 +390,12 @@ public void sendMidiSongSelect(String serializedMidiMessage) { midiOutputDevice.sendMidiSongSelect(Integer.parseInt(split[2])); } } + public void sendMidiSongSelect(String deviceId, int song) { + MidiOutputDevice midiOutputDevice = midiOutputDeviceMap.get(deviceId); + if (midiOutputDevice != null) { + midiOutputDevice.sendMidiSongSelect(song); + } + } public void sendMidiSongPositionPointer(String serializedMidiMessage) { String[] split = serializedMidiMessage.split(","); @@ -302,79 +407,57 @@ public void sendMidiSongPositionPointer(String serializedMidiMessage) { midiOutputDevice.sendMidiSongPositionPointer(Integer.parseInt(split[2])); } } - - public void sendMidiTuneRequest(String serializedMidiMessage) { - String[] split = serializedMidiMessage.split(","); - if (split.length < 1) { - return; + public void sendMidiSongPositionPointer(String deviceId, int position) { + MidiOutputDevice midiOutputDevice = midiOutputDeviceMap.get(deviceId); + if (midiOutputDevice != null) { + midiOutputDevice.sendMidiSongPositionPointer(position); } - MidiOutputDevice midiOutputDevice = midiOutputDeviceMap.get(split[0]); + } + + public void sendMidiTuneRequest(String deviceId) { + MidiOutputDevice midiOutputDevice = midiOutputDeviceMap.get(deviceId); if (midiOutputDevice != null) { midiOutputDevice.sendMidiTuneRequest(); } } - public void sendMidiTimingClock(String serializedMidiMessage) { - String[] split = serializedMidiMessage.split(","); - if (split.length < 1) { - return; - } - MidiOutputDevice midiOutputDevice = midiOutputDeviceMap.get(split[0]); + public void sendMidiTimingClock(String deviceId) { + MidiOutputDevice midiOutputDevice = midiOutputDeviceMap.get(deviceId); if (midiOutputDevice != null) { midiOutputDevice.sendMidiTimingClock(); } } - public void sendMidiStart(String serializedMidiMessage) { - String[] split = serializedMidiMessage.split(","); - if (split.length < 1) { - return; - } - MidiOutputDevice midiOutputDevice = midiOutputDeviceMap.get(split[0]); + public void sendMidiStart(String deviceId) { + MidiOutputDevice midiOutputDevice = midiOutputDeviceMap.get(deviceId); if (midiOutputDevice != null) { midiOutputDevice.sendMidiStart(); } } - public void sendMidiContinue(String serializedMidiMessage) { - String[] split = serializedMidiMessage.split(","); - if (split.length < 1) { - return; - } - MidiOutputDevice midiOutputDevice = midiOutputDeviceMap.get(split[0]); + public void sendMidiContinue(String deviceId) { + MidiOutputDevice midiOutputDevice = midiOutputDeviceMap.get(deviceId); if (midiOutputDevice != null) { midiOutputDevice.sendMidiContinue(); } } - public void sendMidiStop(String serializedMidiMessage) { - String[] split = serializedMidiMessage.split(","); - if (split.length < 2) { - return; - } - MidiOutputDevice midiOutputDevice = midiOutputDeviceMap.get(split[0]); + public void sendMidiStop(String deviceId) { + MidiOutputDevice midiOutputDevice = midiOutputDeviceMap.get(deviceId); if (midiOutputDevice != null) { midiOutputDevice.sendMidiStop(); } } - public void sendMidiActiveSensing(String serializedMidiMessage) { - String[] split = serializedMidiMessage.split(","); - if (split.length < 1) { - return; - } - MidiOutputDevice midiOutputDevice = midiOutputDeviceMap.get(split[0]); + public void sendMidiActiveSensing(String deviceId) { + MidiOutputDevice midiOutputDevice = midiOutputDeviceMap.get(deviceId); if (midiOutputDevice != null) { midiOutputDevice.sendMidiActiveSensing(); } } - public void sendMidiReset(String serializedMidiMessage) { - String[] split = serializedMidiMessage.split(","); - if (split.length < 1) { - return; - } - MidiOutputDevice midiOutputDevice = midiOutputDeviceMap.get(split[0]); + public void sendMidiReset(String deviceId) { + MidiOutputDevice midiOutputDevice = midiOutputDeviceMap.get(deviceId); if (midiOutputDevice != null) { midiOutputDevice.sendMidiReset(); } @@ -384,58 +467,100 @@ public void sendMidiReset(String serializedMidiMessage) { private BleMidiCentralProvider bleMidiCentralProvider; HashMap midiOutputDeviceMap = new HashMap<>(); + OnBleMidiDeviceConnectionListener onMidiDeviceConnectionListener; + OnBleMidiInputEventListener onMidiInputEventListener; + + public void initialize(Context context, OnBleMidiDeviceConnectionListener onMidiDeviceConnectionListener, OnBleMidiInputEventListener onMidiInputEventListener) + { + this.onMidiDeviceConnectionListener = onMidiDeviceConnectionListener; + this.onMidiInputEventListener = onMidiInputEventListener; + initialize(context); + } + public void initialize(Context context) { bleMidiCentralProvider = new BleMidiCentralProvider(context); - bleMidiCentralProvider.setOnMidiDeviceAttachedListener(new OnMidiDeviceAttachedListener() { + bleMidiCentralProvider.setOnMidiDeviceAttachedListener(new jp.kshoji.blemidi.listener.OnMidiDeviceAttachedListener() { @Override public void onMidiInputDeviceAttached(@NonNull MidiInputDevice midiInputDevice) { midiInputDevice.setOnMidiInputEventListener(midiInputEventListener); + if (onMidiDeviceConnectionListener != null) { + onMidiDeviceConnectionListener.onMidiInputDeviceAttached(midiInputDevice.getDeviceAddress()); + return; + } UnityPlayer.UnitySendMessage(GAME_OBJECT_NAME, "OnMidiInputDeviceAttached", midiInputDevice.getDeviceAddress()); } @Override public void onMidiOutputDeviceAttached(@NonNull MidiOutputDevice midiOutputDevice) { midiOutputDeviceMap.put(midiOutputDevice.getDeviceAddress(), midiOutputDevice); + if (onMidiDeviceConnectionListener != null) { + onMidiDeviceConnectionListener.onMidiOutputDeviceAttached(midiOutputDevice.getDeviceAddress()); + return; + } UnityPlayer.UnitySendMessage(GAME_OBJECT_NAME, "OnMidiOutputDeviceAttached", midiOutputDevice.getDeviceAddress()); } }); - bleMidiCentralProvider.setOnMidiDeviceDetachedListener(new OnMidiDeviceDetachedListener() { + bleMidiCentralProvider.setOnMidiDeviceDetachedListener(new jp.kshoji.blemidi.listener.OnMidiDeviceDetachedListener() { @Override public void onMidiInputDeviceDetached(@NonNull MidiInputDevice midiInputDevice) { + if (onMidiDeviceConnectionListener != null) { + onMidiDeviceConnectionListener.onMidiInputDeviceDetached(midiInputDevice.getDeviceAddress()); + return; + } UnityPlayer.UnitySendMessage(GAME_OBJECT_NAME, "OnMidiInputDeviceDetached", midiInputDevice.getDeviceAddress()); } @Override public void onMidiOutputDeviceDetached(@NonNull MidiOutputDevice midiOutputDevice) { midiOutputDeviceMap.remove(midiOutputDevice.getDeviceAddress()); + if (onMidiDeviceConnectionListener != null) { + onMidiDeviceConnectionListener.onMidiOutputDeviceDetached(midiOutputDevice.getDeviceAddress()); + return; + } UnityPlayer.UnitySendMessage(GAME_OBJECT_NAME, "OnMidiOutputDeviceDetached", midiOutputDevice.getDeviceAddress()); } }); bleMidiPeripheralProvider = new BleMidiPeripheralProvider(context); - bleMidiPeripheralProvider.setOnMidiDeviceAttachedListener(new OnMidiDeviceAttachedListener() { + bleMidiPeripheralProvider.setOnMidiDeviceAttachedListener(new jp.kshoji.blemidi.listener.OnMidiDeviceAttachedListener() { @Override public void onMidiInputDeviceAttached(@NonNull MidiInputDevice midiInputDevice) { midiInputDevice.setOnMidiInputEventListener(midiInputEventListener); + if (onMidiDeviceConnectionListener != null) { + onMidiDeviceConnectionListener.onMidiInputDeviceAttached(midiInputDevice.getDeviceAddress()); + return; + } UnityPlayer.UnitySendMessage(GAME_OBJECT_NAME, "OnMidiInputDeviceAttached", midiInputDevice.getDeviceAddress()); } @Override public void onMidiOutputDeviceAttached(@NonNull MidiOutputDevice midiOutputDevice) { midiOutputDeviceMap.put(midiOutputDevice.getDeviceAddress(), midiOutputDevice); + if (onMidiDeviceConnectionListener != null) { + onMidiDeviceConnectionListener.onMidiOutputDeviceAttached(midiOutputDevice.getDeviceAddress()); + return; + } UnityPlayer.UnitySendMessage(GAME_OBJECT_NAME, "OnMidiOutputDeviceAttached", midiOutputDevice.getDeviceAddress()); } }); - bleMidiPeripheralProvider.setOnMidiDeviceDetachedListener(new OnMidiDeviceDetachedListener() { + bleMidiPeripheralProvider.setOnMidiDeviceDetachedListener(new jp.kshoji.blemidi.listener.OnMidiDeviceDetachedListener() { @Override public void onMidiInputDeviceDetached(@NonNull MidiInputDevice midiInputDevice) { + if (onMidiDeviceConnectionListener != null) { + onMidiDeviceConnectionListener.onMidiInputDeviceDetached(midiInputDevice.getDeviceAddress()); + return; + } UnityPlayer.UnitySendMessage(GAME_OBJECT_NAME, "OnMidiInputDeviceDetached", midiInputDevice.getDeviceAddress()); } @Override public void onMidiOutputDeviceDetached(@NonNull MidiOutputDevice midiOutputDevice) { midiOutputDeviceMap.remove(midiOutputDevice.getDeviceAddress()); + if (onMidiDeviceConnectionListener != null) { + onMidiDeviceConnectionListener.onMidiOutputDeviceDetached(midiOutputDevice.getDeviceAddress()); + return; + } UnityPlayer.UnitySendMessage(GAME_OBJECT_NAME, "OnMidiOutputDeviceDetached", midiOutputDevice.getDeviceAddress()); } }); diff --git a/BLE-MIDI-library/src/main/java/jp/kshoji/unity/midi/OnBleMidiDeviceConnectionListener.java b/BLE-MIDI-library/src/main/java/jp/kshoji/unity/midi/OnBleMidiDeviceConnectionListener.java new file mode 100644 index 0000000..580f064 --- /dev/null +++ b/BLE-MIDI-library/src/main/java/jp/kshoji/unity/midi/OnBleMidiDeviceConnectionListener.java @@ -0,0 +1,37 @@ +package jp.kshoji.unity.midi; + +/** + * Listener for MIDI connection events + * + * @author K.Shoji + */ +public interface OnBleMidiDeviceConnectionListener { + + /** + * MIDI input device has been attached + * + * @param deviceId attached MIDI Input device ID + */ + void onMidiInputDeviceAttached(String deviceId); + + /** + * MIDI output device has been attached + * + * @param deviceId attached MIDI Output device ID + */ + void onMidiOutputDeviceAttached(String deviceId); + + /** + * MIDI input device has been detached + * + * @param deviceId detached MIDI Input device ID + */ + void onMidiInputDeviceDetached(String deviceId); + + /** + * MIDI output device has been detached + * + * @param deviceId detached MIDI Output device ID + */ + void onMidiOutputDeviceDetached(String deviceId); +} diff --git a/BLE-MIDI-library/src/main/java/jp/kshoji/unity/midi/OnBleMidiInputEventListener.java b/BLE-MIDI-library/src/main/java/jp/kshoji/unity/midi/OnBleMidiInputEventListener.java new file mode 100644 index 0000000..1a8ac15 --- /dev/null +++ b/BLE-MIDI-library/src/main/java/jp/kshoji/unity/midi/OnBleMidiInputEventListener.java @@ -0,0 +1,157 @@ +package jp.kshoji.unity.midi; + +/** + * Listener for MIDI events + * + * @author K.Shoji + */ +public interface OnBleMidiInputEventListener { + + /** + * SysEx + * + * @param deviceId the device sent this message + * @param systemExclusive received message + */ + void onMidiSystemExclusive(String deviceId, byte[] systemExclusive); + + /** + * Note-off + * + * @param deviceId the device sent this message + * @param channel 0-15 + * @param note 0-127 + * @param velocity 0-127 + */ + void onMidiNoteOff(String deviceId, int channel, int note, int velocity); + + /** + * Note-on + * + * @param deviceId the device sent this message + * @param channel 0-15 + * @param note 0-127 + * @param velocity 0-127 + */ + void onMidiNoteOn(String deviceId, int channel, int note, int velocity); + + /** + * Poly-KeyPress + * + * @param deviceId the device sent this message + * @param channel 0-15 + * @param note 0-127 + * @param pressure 0-127 + */ + void onMidiPolyphonicAftertouch(String deviceId, int channel, int note, int pressure); + + /** + * Control Change + * + * @param deviceId the device sent this message + * @param channel 0-15 + * @param function 0-127 + * @param value 0-127 + */ + void onMidiControlChange(String deviceId, int channel, int function, int value); + + /** + * Program Change + * + * @param deviceId the device sent this message + * @param channel 0-15 + * @param program 0-127 + */ + void onMidiProgramChange(String deviceId, int channel, int program); + + /** + * Channel Pressure + * + * @param deviceId the device sent this message + * @param channel 0-15 + * @param pressure 0-127 + */ + void onMidiChannelAftertouch(String deviceId, int channel, int pressure); + + /** + * PitchBend Change + * + * @param deviceId the device sent this message + * @param channel 0-15 + * @param amount 0(low)-8192(center)-16383(high) + */ + void onMidiPitchWheel(String deviceId, int channel, int amount); + + /** + * MIDI Time Code(MTC) Quarter Frame + * + * @param deviceId the device sent this message + * @param timing 0-16383 + */ + void onMidiTimeCodeQuarterFrame(String deviceId, int timing); + + /** + * Song Select + * + * @param deviceId the device sent this message + * @param song 0-127 + */ + void onMidiSongSelect(String deviceId, int song); + + /** + * Song Position Pointer + * + * @param deviceId the device sent this message + * @param position 0-16383 + */ + void onMidiSongPositionPointer(String deviceId, int position); + + /** + * Tune Request + * + * @param deviceId the device sent this message + */ + void onMidiTuneRequest(String deviceId); + + /** + * Timing Clock + * + * @param deviceId the device sent this message + */ + void onMidiTimingClock(String deviceId); + + /** + * Start Playing + * + * @param deviceId the device sent this message + */ + void onMidiStart(String deviceId); + + /** + * Continue Playing + * + * @param deviceId the device sent this message + */ + void onMidiContinue(String deviceId); + + /** + * Stop Playing + * + * @param deviceId the device sent this message + */ + void onMidiStop(String deviceId); + + /** + * Active Sensing + * + * @param deviceId the device sent this message + */ + void onMidiActiveSensing(String deviceId); + + /** + * Reset Device + * + * @param deviceId the device sent this message + */ + void onMidiReset(String deviceId); +} diff --git a/UnityPlayerMock/src/main/java/com/unity3d/player/UnityPlayer.java b/UnityPlayerMock/src/main/java/com/unity3d/player/UnityPlayer.java index 998d083..657c5ab 100644 --- a/UnityPlayerMock/src/main/java/com/unity3d/player/UnityPlayer.java +++ b/UnityPlayerMock/src/main/java/com/unity3d/player/UnityPlayer.java @@ -1,6 +1,6 @@ package com.unity3d.player; public class UnityPlayer { - public static void UnitySendMessage(String gameObjectName, String onMidiInputDeviceAttached, String deviceAddress) { + public static void UnitySendMessage(String gameObjectName, String methodName, String parameter) { } } From 644e6b2f554385e0bf8cecb07f0c88ec2fc3455f Mon Sep 17 00:00:00 2001 From: Kaoru Shoji <0x0badc0de@gmail.com> Date: Tue, 16 Aug 2022 05:47:08 +0900 Subject: [PATCH 07/14] Bump targetSdk to 32 --- BLE-MIDI-library/build.gradle | 3 +- BLE-MIDI-library/src/main/AndroidManifest.xml | 4 ++ .../blemidi/central/BleMidiCallback.java | 18 +++---- .../central/BleMidiCentralProvider.java | 14 ++--- .../peripheral/BleMidiPeripheralProvider.java | 24 ++++----- .../java/jp/kshoji/blemidi/util/BleUtils.java | 16 +----- .../javax/sound/midi/BleMidiSystem.java | 13 +++-- sample-wear/build.gradle | 8 +-- sample-wear/src/main/AndroidManifest.xml | 14 +++-- sample/src/main/AndroidManifest.xml | 8 ++- .../blemidi/sample/CentralActivity.java | 16 +++--- .../blemidi/sample/PeripheralActivity.java | 24 ++++----- sample/src/main/res/layout/activity_main.xml | 53 ++++++++++++------- sample/src/main/res/values/strings.xml | 7 +++ 14 files changed, 126 insertions(+), 96 deletions(-) diff --git a/BLE-MIDI-library/build.gradle b/BLE-MIDI-library/build.gradle index 3146d8e..6fb8cd3 100644 --- a/BLE-MIDI-library/build.gradle +++ b/BLE-MIDI-library/build.gradle @@ -1,10 +1,11 @@ apply plugin: 'com.android.library' android { - compileSdkVersion 29 + compileSdkVersion 32 defaultConfig { minSdkVersion 18 + targetSdkVersion 32 } compileOptions { diff --git a/BLE-MIDI-library/src/main/AndroidManifest.xml b/BLE-MIDI-library/src/main/AndroidManifest.xml index c0b7b6e..969a67c 100644 --- a/BLE-MIDI-library/src/main/AndroidManifest.xml +++ b/BLE-MIDI-library/src/main/AndroidManifest.xml @@ -1,6 +1,10 @@ + + + diff --git a/BLE-MIDI-library/src/main/java/jp/kshoji/blemidi/central/BleMidiCallback.java b/BLE-MIDI-library/src/main/java/jp/kshoji/blemidi/central/BleMidiCallback.java index 3341df8..89682ce 100644 --- a/BLE-MIDI-library/src/main/java/jp/kshoji/blemidi/central/BleMidiCallback.java +++ b/BLE-MIDI-library/src/main/java/jp/kshoji/blemidi/central/BleMidiCallback.java @@ -79,7 +79,7 @@ boolean isConnected(@NonNull BluetoothDevice device) { private volatile static Object gattDiscoverServicesLock = null; @Override - public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { + public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) throws SecurityException { super.onConnectionStateChange(gatt, status, newState); // In this method, the `status` parameter shall be ignored. // so, look `newState` parameter only. @@ -296,7 +296,7 @@ void disconnectDevice(@NonNull MidiOutputDevice midiOutputDevice) { * * @param deviceAddress the device address from {@link android.bluetooth.BluetoothGatt} */ - private void disconnectByDeviceAddress(@NonNull String deviceAddress) { + private void disconnectByDeviceAddress(@NonNull String deviceAddress) throws SecurityException { synchronized (deviceAddressGattMap) { List bluetoothGatts = deviceAddressGattMap.get(deviceAddress); @@ -347,7 +347,7 @@ private void disconnectByDeviceAddress(@NonNull String deviceAddress) { /** * Terminates callback */ - public void terminate() { + public void terminate() throws SecurityException { synchronized (deviceAddressGattMap) { for (List bluetoothGatts : deviceAddressGattMap.values()) { if (bluetoothGatts != null) { @@ -514,7 +514,7 @@ private static final class InternalMidiInputDevice extends MidiInputDevice { * @param bluetoothGatt the gatt of device * @throws IllegalArgumentException if specified gatt doesn't contain BLE MIDI service */ - public InternalMidiInputDevice(@NonNull final Context context, @NonNull final BluetoothGatt bluetoothGatt) throws IllegalArgumentException { + public InternalMidiInputDevice(@NonNull final Context context, @NonNull final BluetoothGatt bluetoothGatt) throws IllegalArgumentException, SecurityException { super(); this.bluetoothGatt = bluetoothGatt; @@ -543,7 +543,7 @@ void stop() { /** * Configure the device as BLE Central */ - public void configureAsCentralDevice() { + public void configureAsCentralDevice() throws SecurityException { bluetoothGatt.setCharacteristicNotification(midiInputCharacteristic, true); List descriptors = midiInputCharacteristic.getDescriptors(); @@ -564,7 +564,7 @@ public void setOnMidiInputEventListener(OnMidiInputEventListener midiInputEventL @NonNull @Override - public String getDeviceName() { + public String getDeviceName() throws SecurityException { return bluetoothGatt.getDevice().getName(); } @@ -604,7 +604,7 @@ private static final class InternalMidiOutputDevice extends MidiOutputDevice { * @param bluetoothGatt the gatt of device * @throws IllegalArgumentException if specified gatt doesn't contain BLE MIDI service */ - public InternalMidiOutputDevice(@NonNull final Context context, @NonNull final BluetoothGatt bluetoothGatt) throws IllegalArgumentException { + public InternalMidiOutputDevice(@NonNull final Context context, @NonNull final BluetoothGatt bluetoothGatt) throws IllegalArgumentException, SecurityException { super(); this.bluetoothGatt = bluetoothGatt; @@ -631,7 +631,7 @@ public void configureAsCentralDevice() { } @Override - public void transferData(@NonNull byte[] writeBuffer) { + public void transferData(@NonNull byte[] writeBuffer) throws SecurityException { midiOutputCharacteristic.setValue(writeBuffer); try { @@ -644,7 +644,7 @@ public void transferData(@NonNull byte[] writeBuffer) { @NonNull @Override - public String getDeviceName() { + public String getDeviceName() throws SecurityException { return bluetoothGatt.getDevice().getName(); } diff --git a/BLE-MIDI-library/src/main/java/jp/kshoji/blemidi/central/BleMidiCentralProvider.java b/BLE-MIDI-library/src/main/java/jp/kshoji/blemidi/central/BleMidiCentralProvider.java index 66179b8..3e457d7 100644 --- a/BLE-MIDI-library/src/main/java/jp/kshoji/blemidi/central/BleMidiCentralProvider.java +++ b/BLE-MIDI-library/src/main/java/jp/kshoji/blemidi/central/BleMidiCentralProvider.java @@ -46,7 +46,7 @@ public final class BleMidiCentralProvider { */ private final BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() { @Override - public void onLeScan(final BluetoothDevice bluetoothDevice, int rssi, byte[] scanRecord) { + public void onLeScan(final BluetoothDevice bluetoothDevice, int rssi, byte[] scanRecord) throws SecurityException { if (bluetoothDevice.getType() != BluetoothDevice.DEVICE_TYPE_LE && bluetoothDevice.getType() != BluetoothDevice.DEVICE_TYPE_DUAL) { return; @@ -86,7 +86,7 @@ public void run() { * @param context the context */ @SuppressLint("NewApi") - public BleMidiCentralProvider(@NonNull final Context context) throws UnsupportedOperationException { + public BleMidiCentralProvider(@NonNull final Context context) throws UnsupportedOperationException, SecurityException { if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE) == false) { throw new UnsupportedOperationException("Bluetooth LE not supported on this device."); } @@ -107,7 +107,7 @@ public BleMidiCentralProvider(@NonNull final Context context) throws Unsupported scanCallback = new ScanCallback() { @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override - public void onScanResult(int callbackType, ScanResult result) { + public void onScanResult(int callbackType, ScanResult result) throws SecurityException { super.onScanResult(callbackType, result); if (callbackType == ScanSettings.CALLBACK_TYPE_ALL_MATCHES) { @@ -121,7 +121,7 @@ public void onScanResult(int callbackType, ScanResult result) { if (context instanceof Activity) { ((Activity) context).runOnUiThread(new Runnable() { @Override - public void run() { + public void run() throws SecurityException { bluetoothDevice.connectGatt(BleMidiCentralProvider.this.context, true, midiCallback); } }); @@ -131,7 +131,7 @@ public void run() { } else { handler.post(new Runnable() { @Override - public void run() { + public void run() throws SecurityException { bluetoothDevice.connectGatt(BleMidiCentralProvider.this.context, true, midiCallback); } }); @@ -171,7 +171,7 @@ public void setRequestPairing(boolean needsPairing) { * @param timeoutInMilliSeconds 0 or negative value : no timeout */ @SuppressLint({ "Deprecation", "NewApi" }) - public void startScanDevice(int timeoutInMilliSeconds) { + public void startScanDevice(int timeoutInMilliSeconds) throws SecurityException { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { BluetoothLeScanner bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner(); List scanFilters = BleMidiDeviceUtils.getBleMidiScanFilters(context); @@ -210,7 +210,7 @@ public void run() { * Stops to scan devices */ @SuppressLint({ "Deprecation", "NewApi" }) - public void stopScanDevice() { + public void stopScanDevice() throws SecurityException { try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { final BluetoothLeScanner bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner(); diff --git a/BLE-MIDI-library/src/main/java/jp/kshoji/blemidi/peripheral/BleMidiPeripheralProvider.java b/BLE-MIDI-library/src/main/java/jp/kshoji/blemidi/peripheral/BleMidiPeripheralProvider.java index d164d21..334c8d9 100644 --- a/BLE-MIDI-library/src/main/java/jp/kshoji/blemidi/peripheral/BleMidiPeripheralProvider.java +++ b/BLE-MIDI-library/src/main/java/jp/kshoji/blemidi/peripheral/BleMidiPeripheralProvider.java @@ -141,7 +141,7 @@ public BleMidiPeripheralProvider(final Context context) throws UnsupportedOperat /** * Starts advertising */ - public void startAdvertising() { + public void startAdvertising() throws SecurityException { // register Gatt service to Gatt server if (gattServer == null) { gattServer = bluetoothManager.openGattServer(context, gattServerCallback); @@ -212,7 +212,7 @@ public void startAdvertising() { /** * Stops advertising */ - public void stopAdvertising() { + public void stopAdvertising() throws SecurityException { try { bluetoothLeAdvertiser.stopAdvertising(advertiseCallback); } catch (IllegalStateException ignored) { @@ -257,7 +257,7 @@ public void disconnectDevice(@NonNull MidiOutputDevice midiOutputDevice) { */ private final BluetoothGattCallback disconnectCallback = new BluetoothGattCallback() { @Override - public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { + public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) throws SecurityException { super.onConnectionStateChange(gatt, status, newState); Log.d(Constants.TAG, "onConnectionStateChange status: " + status + ", newState: " + newState); // disconnect the device @@ -272,7 +272,7 @@ public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState * * @param deviceAddress the device address from {@link android.bluetooth.BluetoothGatt} */ - private void disconnectByDeviceAddress(@NonNull String deviceAddress) { + private void disconnectByDeviceAddress(@NonNull String deviceAddress) throws SecurityException { synchronized (bluetoothDevicesMap) { BluetoothDevice bluetoothDevice = bluetoothDevicesMap.get(deviceAddress); if (bluetoothDevice != null) { @@ -285,7 +285,7 @@ private void disconnectByDeviceAddress(@NonNull String deviceAddress) { /** * Terminates provider */ - public void terminate() { + public void terminate() throws SecurityException { stopAdvertising(); synchronized (bluetoothDevicesMap) { @@ -373,7 +373,7 @@ public void onConnectionStateChange(BluetoothDevice device, int status, int newS } @Override - public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) { + public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) throws SecurityException { super.onCharacteristicReadRequest(device, requestId, offset, characteristic); UUID characteristicUuid = characteristic.getUuid(); @@ -398,7 +398,7 @@ public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, i } @Override - public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) { + public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) throws SecurityException { super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value); if (BleUuidUtils.matches(characteristic.getUuid(), CHARACTERISTIC_BLE_MIDI)) { @@ -416,7 +416,7 @@ public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, } @Override - public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) { + public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) throws SecurityException { super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value); byte[] descriptorValue = descriptor.getValue(); @@ -430,7 +430,7 @@ public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, Blue } @Override - public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) { + public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) throws SecurityException { super.onDescriptorReadRequest(device, requestId, offset, descriptor); if (offset == 0) { @@ -587,7 +587,7 @@ public void setOnMidiInputEventListener(OnMidiInputEventListener midiInputEventL @NonNull @Override - public String getDeviceName() { + public String getDeviceName() throws SecurityException { if (TextUtils.isEmpty(bluetoothDevice.getName())) { return bluetoothDevice.getAddress(); } @@ -635,7 +635,7 @@ public InternalMidiOutputDevice(@NonNull final BluetoothDevice bluetoothDevice, @NonNull @Override - public String getDeviceName() { + public String getDeviceName() throws SecurityException { if (TextUtils.isEmpty(bluetoothDevice.getName())) { return bluetoothDevice.getAddress(); } @@ -643,7 +643,7 @@ public String getDeviceName() { } @Override - public void transferData(@NonNull byte[] writeBuffer) { + public void transferData(@NonNull byte[] writeBuffer) throws SecurityException { midiOutputCharacteristic.setValue(writeBuffer); try { diff --git a/BLE-MIDI-library/src/main/java/jp/kshoji/blemidi/util/BleUtils.java b/BLE-MIDI-library/src/main/java/jp/kshoji/blemidi/util/BleUtils.java index 125a8e0..d2bbb13 100644 --- a/BLE-MIDI-library/src/main/java/jp/kshoji/blemidi/util/BleUtils.java +++ b/BLE-MIDI-library/src/main/java/jp/kshoji/blemidi/util/BleUtils.java @@ -31,13 +31,7 @@ public static boolean isBleSupported(@NonNull final Context context) { final BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE); - final BluetoothAdapter bluetoothAdapter; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - bluetoothAdapter = bluetoothManager.getAdapter(); - } else { - bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); - } - + final BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter(); if (bluetoothAdapter != null) { return true; } @@ -81,13 +75,7 @@ public static boolean isBluetoothEnabled(@NonNull final Context context) { return false; } - final BluetoothAdapter bluetoothAdapter; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - bluetoothAdapter = bluetoothManager.getAdapter(); - } else { - bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); - } - + final BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter(); if (bluetoothAdapter == null) { return false; } diff --git a/BLE-MIDI-library/src/main/java/jp/kshoji/javax/sound/midi/BleMidiSystem.java b/BLE-MIDI-library/src/main/java/jp/kshoji/javax/sound/midi/BleMidiSystem.java index 98bcb7c..c54d35b 100644 --- a/BLE-MIDI-library/src/main/java/jp/kshoji/javax/sound/midi/BleMidiSystem.java +++ b/BLE-MIDI-library/src/main/java/jp/kshoji/javax/sound/midi/BleMidiSystem.java @@ -22,8 +22,8 @@ * @author K.Shoji */ public final class BleMidiSystem implements OnMidiDeviceAttachedListener, OnMidiDeviceDetachedListener { - private static BleMidiPeripheralProvider peripheralProvider; - private static BleMidiCentralProvider centralProvider; + private BleMidiPeripheralProvider peripheralProvider; + private BleMidiCentralProvider centralProvider; private final Map midiDeviceMap = new HashMap<>(); private final Map midiSynthesizerMap = new HashMap<>(); @@ -44,12 +44,15 @@ public BleMidiSystem(@NonNull final Context context) { public void initialize() { if (BleUtils.isBleSupported(context)) { if (BleUtils.isBlePeripheralSupported(context)) { - peripheralProvider = new BleMidiPeripheralProvider(context); - + if (peripheralProvider == null) { + peripheralProvider = new BleMidiPeripheralProvider(context); + } peripheralProvider.setOnMidiDeviceAttachedListener(this); } - centralProvider = new BleMidiCentralProvider(context); + if (centralProvider == null) { + centralProvider = new BleMidiCentralProvider(context); + } centralProvider.setOnMidiDeviceAttachedListener(this); } } diff --git a/sample-wear/build.gradle b/sample-wear/build.gradle index 17a712b..8725420 100644 --- a/sample-wear/build.gradle +++ b/sample-wear/build.gradle @@ -1,12 +1,12 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 30 + compileSdkVersion 32 defaultConfig { applicationId "jp.kshoji.blemidi.sample" minSdkVersion 22 - targetSdkVersion 30 + targetSdkVersion 32 versionCode 3 versionName "1.2" } @@ -34,7 +34,7 @@ repositories { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation project(':BLE-MIDI-library') - implementation 'com.google.android.support:wearable:2.8.1' - compileOnly 'com.google.android.wearable:wearable:2.8.1' + implementation 'com.google.android.support:wearable:2.9.0' + compileOnly 'com.google.android.wearable:wearable:2.9.0' implementation 'com.google.android.gms:play-services-wearable:17.1.0' } diff --git a/sample-wear/src/main/AndroidManifest.xml b/sample-wear/src/main/AndroidManifest.xml index 087bbe1..11ba6d2 100644 --- a/sample-wear/src/main/AndroidManifest.xml +++ b/sample-wear/src/main/AndroidManifest.xml @@ -4,8 +4,12 @@ - - + + + + + + @@ -19,12 +23,16 @@ android:label="@string/app_name" android:theme="@android:style/Theme.DeviceDefault"> + + android:launchMode="singleTask" + android:exported="true"> diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index 5deb7b9..f276227 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -2,7 +2,13 @@ - + + + + + + + + android:text="@string/disconnect" /> + android:textOff="@string/thru_off" + android:textOn="@string/thru_on" /> @@ -68,98 +68,111 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" - android:tag="0" /> + android:tag="0" + style="?android:attr/buttonBarButtonStyle" />