diff --git a/examples/Demo/Builds/Android/app/src/main/java/com/yourcompany/jucedemo/JuceDemo.java b/examples/Demo/Builds/Android/app/src/main/java/com/yourcompany/jucedemo/JuceDemo.java index 1e122134ba..7cc7f459e0 100644 --- a/examples/Demo/Builds/Android/app/src/main/java/com/yourcompany/jucedemo/JuceDemo.java +++ b/examples/Demo/Builds/Android/app/src/main/java/com/yourcompany/jucedemo/JuceDemo.java @@ -179,9 +179,9 @@ public class JuceDemo extends Activity return address; } - public boolean isBluetoothDevicePaired (String address) + public int getBluetoothDeviceStatus (String address) { - return false; + return 0; } public void startStopScan (boolean shouldStart) diff --git a/examples/MidiTest/Builds/Android/app/src/main/java/com/yourcompany/miditest/MidiTest.java b/examples/MidiTest/Builds/Android/app/src/main/java/com/yourcompany/miditest/MidiTest.java index 44a2557371..bc8b235916 100644 --- a/examples/MidiTest/Builds/Android/app/src/main/java/com/yourcompany/miditest/MidiTest.java +++ b/examples/MidiTest/Builds/Android/app/src/main/java/com/yourcompany/miditest/MidiTest.java @@ -194,9 +194,9 @@ public class MidiTest extends Activity return btDevice.getName(); } - public boolean isBluetoothDevicePaired (String address) + public int getBluetoothDeviceStatus (String address) { - return getAndroidMidiDeviceManager().isBluetoothDevicePaired (address); + return getAndroidMidiDeviceManager().getBluetoothDeviceStatus (address); } public void startStopScan (boolean shouldStart) @@ -487,7 +487,78 @@ public class MidiTest extends Activity //============================================================================== public class MidiDeviceManager extends MidiManager.DeviceCallback implements MidiManager.OnDeviceOpenedListener { + //============================================================================== + private class MidiDeviceOpenTask extends java.util.TimerTask + { + public MidiDeviceOpenTask (MidiDeviceManager deviceManager, MidiDevice device) + { + owner = deviceManager; + midiDevice = device; + } + + @Override + public boolean cancel() + { + synchronized (MidiDeviceOpenTask.class) + { + owner = null; + boolean retval = super.cancel(); + + if (midiDevice != null) + { + try + { + midiDevice.close(); + } + catch (IOException e) + {} + + midiDevice = null; + } + + return retval; + } + } + + public String getBluetoothAddress() + { + synchronized (MidiDeviceOpenTask.class) + { + if (midiDevice != null) + { + MidiDeviceInfo info = midiDevice.getInfo(); + if (info.getType() == MidiDeviceInfo.TYPE_BLUETOOTH) + { + BluetoothDevice btDevice = (BluetoothDevice) info.getProperties().get (info.PROPERTY_BLUETOOTH_DEVICE); + if (btDevice != null) + return btDevice.getAddress(); + } + } + } + + return ""; + } + public int getID() + { + return midiDevice.getInfo().getId(); + } + + @Override + public void run() + { + synchronized (MidiDeviceOpenTask.class) + { + if (owner != null && midiDevice != null) + owner.onDeviceOpenedDelayed (midiDevice); + } + } + + private MidiDeviceManager owner; + private MidiDevice midiDevice; + } + + //============================================================================== public MidiDeviceManager() { manager = (MidiManager) getSystemService (MIDI_SERVICE); @@ -500,6 +571,8 @@ public class MidiTest extends Activity openPorts = new HashMap> (); midiDevices = new ArrayList(); + openTasks = new HashMap(); + btDevicesPairing = new HashSet(); MidiDeviceInfo[] foundDevices = manager.getDevices(); for (MidiDeviceInfo info : foundDevices) @@ -512,6 +585,16 @@ public class MidiTest extends Activity { manager.unregisterDeviceCallback (this); + synchronized (MidiDeviceManager.class) + { + btDevicesPairing.clear(); + + for (Integer deviceID : openTasks.keySet()) + openTasks.get (deviceID).cancel(); + + openTasks = null; + } + for (MidiPortPath key : openPorts.keySet()) openPorts.get (key).get().close(); @@ -606,21 +689,62 @@ public class MidiTest extends Activity return openMidiPortWithJuceIndex (index, 0, false); } - public boolean isBluetoothDevicePaired (String address) + /* 0: unpaired, 1: paired, 2: pairing */ + public int getBluetoothDeviceStatus (String address) { - return (findMidiDeviceForBluetoothAddress (address) != null); + synchronized (MidiDeviceManager.class) + { + if (! address.isEmpty()) + { + if (findMidiDeviceForBluetoothAddress (address) != null) + return 1; + + if (btDevicesPairing.contains (address)) + return 2; + + if (findOpenTaskForBluetoothAddress (address) != null) + return 2; + } + } + + return 0; } public boolean pairBluetoothDevice (BluetoothDevice btDevice) { - manager.openBluetoothDevice(btDevice, this, null); + String btAddress = btDevice.getAddress(); + if (btAddress.isEmpty()) + return false; + + synchronized (MidiDeviceManager.class) + { + if (getBluetoothDeviceStatus (btAddress) != 0) + return false; + + btDevicesPairing.add (btDevice.getAddress()); + manager.openBluetoothDevice(btDevice, this, null); + } + return true; } public void unpairBluetoothDevice (String address) { + if (address.isEmpty()) + return; + synchronized (MidiDeviceManager.class) { + btDevicesPairing.remove (address); + + MidiDeviceOpenTask openTask = findOpenTaskForBluetoothAddress (address); + if (openTask != null) + { + int deviceID = openTask.getID(); + openTask.cancel(); + openTasks.remove (deviceID); + } + MidiDevice midiDevice = findMidiDeviceForBluetoothAddress (address); if (midiDevice != null) { @@ -653,6 +777,18 @@ public class MidiTest extends Activity return null; } + private MidiDeviceOpenTask findOpenTaskForBluetoothAddress (String address) + { + for (Integer deviceID : openTasks.keySet()) + { + MidiDeviceOpenTask openTask = openTasks.get (deviceID); + if (openTask.getBluetoothAddress().equals (address)) + return openTask; + } + + return null; + } + public void removePort (MidiPortPath path) { openPorts.remove (path); @@ -719,9 +855,68 @@ public class MidiTest extends Activity { synchronized (MidiDeviceManager.class) { - // make sure it's not already there - if (! midiDevices.contains(theDevice)) - midiDevices.add (theDevice); + MidiDeviceInfo info = theDevice.getInfo(); + int deviceID = info.getId(); + + if (! openTasks.containsKey (deviceID)) + { + if (info.getType() == MidiDeviceInfo.TYPE_BLUETOOTH) + { + BluetoothDevice btDevice = (BluetoothDevice) info.getProperties().get (info.PROPERTY_BLUETOOTH_DEVICE); + if (btDevice != null) + { + String btAddress = btDevice.getAddress(); + if (btDevicesPairing.contains (btAddress)) + { + btDevicesPairing.remove (btAddress); + } + else + { + // unpair was called in the mean time + try + { + theDevice.close(); + } + catch (IOException e) + {} + + return; + } + } + } + + MidiDeviceOpenTask openTask = new MidiDeviceOpenTask (this, theDevice); + openTasks.put (deviceID, openTask); + + new java.util.Timer().schedule (openTask, 3000); + } + } + } + + public void onDeviceOpenedDelayed (MidiDevice theDevice) + { + synchronized (MidiDeviceManager.class) + { + int deviceID = theDevice.getInfo().getId(); + + if (openTasks.containsKey (deviceID)) + { + if (! midiDevices.contains(theDevice)) + { + openTasks.remove (deviceID); + midiDevices.add (theDevice); + } + } + else + { + // unpair was called in the mean time + try + { + theDevice.close(); + } + catch (IOException e) + {} + } } } @@ -808,6 +1003,8 @@ public class MidiTest extends Activity } private MidiManager manager; + private HashSet btDevicesPairing; + private HashMap openTasks; private ArrayList midiDevices; private MidiDeviceInfo[] deviceInfos; private HashMap> openPorts; diff --git a/examples/NetworkGraphicsDemo/Builds/Android/app/src/main/java/com/juce/networkgraphicsdemo/JUCENetworkGraphicsDemo.java b/examples/NetworkGraphicsDemo/Builds/Android/app/src/main/java/com/juce/networkgraphicsdemo/JUCENetworkGraphicsDemo.java index 1263e00076..54aedb9b89 100644 --- a/examples/NetworkGraphicsDemo/Builds/Android/app/src/main/java/com/juce/networkgraphicsdemo/JUCENetworkGraphicsDemo.java +++ b/examples/NetworkGraphicsDemo/Builds/Android/app/src/main/java/com/juce/networkgraphicsdemo/JUCENetworkGraphicsDemo.java @@ -179,9 +179,9 @@ public class JUCENetworkGraphicsDemo extends Activity return address; } - public boolean isBluetoothDevicePaired (String address) + public int getBluetoothDeviceStatus (String address) { - return false; + return 0; } public void startStopScan (boolean shouldStart) diff --git a/examples/OSCReceiver/Builds/Android/app/src/main/java/com/yourcompany/oscreceiver/OSCReceiver.java b/examples/OSCReceiver/Builds/Android/app/src/main/java/com/yourcompany/oscreceiver/OSCReceiver.java index fdc895101a..c1d0a7bc57 100644 --- a/examples/OSCReceiver/Builds/Android/app/src/main/java/com/yourcompany/oscreceiver/OSCReceiver.java +++ b/examples/OSCReceiver/Builds/Android/app/src/main/java/com/yourcompany/oscreceiver/OSCReceiver.java @@ -179,9 +179,9 @@ public class OSCReceiver extends Activity return address; } - public boolean isBluetoothDevicePaired (String address) + public int getBluetoothDeviceStatus (String address) { - return false; + return 0; } public void startStopScan (boolean shouldStart) diff --git a/examples/OSCSender/Builds/Android/app/src/main/java/com/yourcompany/oscsender/OSCSender.java b/examples/OSCSender/Builds/Android/app/src/main/java/com/yourcompany/oscsender/OSCSender.java index 75281fa797..bcf707d151 100644 --- a/examples/OSCSender/Builds/Android/app/src/main/java/com/yourcompany/oscsender/OSCSender.java +++ b/examples/OSCSender/Builds/Android/app/src/main/java/com/yourcompany/oscsender/OSCSender.java @@ -179,9 +179,9 @@ public class OSCSender extends Activity return address; } - public boolean isBluetoothDevicePaired (String address) + public int getBluetoothDeviceStatus (String address) { - return false; + return 0; } public void startStopScan (boolean shouldStart) diff --git a/examples/audio plugin demo/Builds/Android/app/src/main/java/com/juce/jucedemoplugin/JuceDemoPlugin.java b/examples/audio plugin demo/Builds/Android/app/src/main/java/com/juce/jucedemoplugin/JuceDemoPlugin.java index 788a8700ea..5fb5eac49e 100644 --- a/examples/audio plugin demo/Builds/Android/app/src/main/java/com/juce/jucedemoplugin/JuceDemoPlugin.java +++ b/examples/audio plugin demo/Builds/Android/app/src/main/java/com/juce/jucedemoplugin/JuceDemoPlugin.java @@ -194,9 +194,9 @@ public class JuceDemoPlugin extends Activity return btDevice.getName(); } - public boolean isBluetoothDevicePaired (String address) + public int getBluetoothDeviceStatus (String address) { - return getAndroidMidiDeviceManager().isBluetoothDevicePaired (address); + return getAndroidMidiDeviceManager().getBluetoothDeviceStatus (address); } public void startStopScan (boolean shouldStart) @@ -487,7 +487,78 @@ public class JuceDemoPlugin extends Activity //============================================================================== public class MidiDeviceManager extends MidiManager.DeviceCallback implements MidiManager.OnDeviceOpenedListener { + //============================================================================== + private class MidiDeviceOpenTask extends java.util.TimerTask + { + public MidiDeviceOpenTask (MidiDeviceManager deviceManager, MidiDevice device) + { + owner = deviceManager; + midiDevice = device; + } + + @Override + public boolean cancel() + { + synchronized (MidiDeviceOpenTask.class) + { + owner = null; + boolean retval = super.cancel(); + + if (midiDevice != null) + { + try + { + midiDevice.close(); + } + catch (IOException e) + {} + + midiDevice = null; + } + + return retval; + } + } + + public String getBluetoothAddress() + { + synchronized (MidiDeviceOpenTask.class) + { + if (midiDevice != null) + { + MidiDeviceInfo info = midiDevice.getInfo(); + if (info.getType() == MidiDeviceInfo.TYPE_BLUETOOTH) + { + BluetoothDevice btDevice = (BluetoothDevice) info.getProperties().get (info.PROPERTY_BLUETOOTH_DEVICE); + if (btDevice != null) + return btDevice.getAddress(); + } + } + } + + return ""; + } + public int getID() + { + return midiDevice.getInfo().getId(); + } + + @Override + public void run() + { + synchronized (MidiDeviceOpenTask.class) + { + if (owner != null && midiDevice != null) + owner.onDeviceOpenedDelayed (midiDevice); + } + } + + private MidiDeviceManager owner; + private MidiDevice midiDevice; + } + + //============================================================================== public MidiDeviceManager() { manager = (MidiManager) getSystemService (MIDI_SERVICE); @@ -500,6 +571,8 @@ public class JuceDemoPlugin extends Activity openPorts = new HashMap> (); midiDevices = new ArrayList(); + openTasks = new HashMap(); + btDevicesPairing = new HashSet(); MidiDeviceInfo[] foundDevices = manager.getDevices(); for (MidiDeviceInfo info : foundDevices) @@ -512,6 +585,16 @@ public class JuceDemoPlugin extends Activity { manager.unregisterDeviceCallback (this); + synchronized (MidiDeviceManager.class) + { + btDevicesPairing.clear(); + + for (Integer deviceID : openTasks.keySet()) + openTasks.get (deviceID).cancel(); + + openTasks = null; + } + for (MidiPortPath key : openPorts.keySet()) openPorts.get (key).get().close(); @@ -606,21 +689,62 @@ public class JuceDemoPlugin extends Activity return openMidiPortWithJuceIndex (index, 0, false); } - public boolean isBluetoothDevicePaired (String address) + /* 0: unpaired, 1: paired, 2: pairing */ + public int getBluetoothDeviceStatus (String address) { - return (findMidiDeviceForBluetoothAddress (address) != null); + synchronized (MidiDeviceManager.class) + { + if (! address.isEmpty()) + { + if (findMidiDeviceForBluetoothAddress (address) != null) + return 1; + + if (btDevicesPairing.contains (address)) + return 2; + + if (findOpenTaskForBluetoothAddress (address) != null) + return 2; + } + } + + return 0; } public boolean pairBluetoothDevice (BluetoothDevice btDevice) { - manager.openBluetoothDevice(btDevice, this, null); + String btAddress = btDevice.getAddress(); + if (btAddress.isEmpty()) + return false; + + synchronized (MidiDeviceManager.class) + { + if (getBluetoothDeviceStatus (btAddress) != 0) + return false; + + btDevicesPairing.add (btDevice.getAddress()); + manager.openBluetoothDevice(btDevice, this, null); + } + return true; } public void unpairBluetoothDevice (String address) { + if (address.isEmpty()) + return; + synchronized (MidiDeviceManager.class) { + btDevicesPairing.remove (address); + + MidiDeviceOpenTask openTask = findOpenTaskForBluetoothAddress (address); + if (openTask != null) + { + int deviceID = openTask.getID(); + openTask.cancel(); + openTasks.remove (deviceID); + } + MidiDevice midiDevice = findMidiDeviceForBluetoothAddress (address); if (midiDevice != null) { @@ -653,6 +777,18 @@ public class JuceDemoPlugin extends Activity return null; } + private MidiDeviceOpenTask findOpenTaskForBluetoothAddress (String address) + { + for (Integer deviceID : openTasks.keySet()) + { + MidiDeviceOpenTask openTask = openTasks.get (deviceID); + if (openTask.getBluetoothAddress().equals (address)) + return openTask; + } + + return null; + } + public void removePort (MidiPortPath path) { openPorts.remove (path); @@ -719,9 +855,68 @@ public class JuceDemoPlugin extends Activity { synchronized (MidiDeviceManager.class) { - // make sure it's not already there - if (! midiDevices.contains(theDevice)) - midiDevices.add (theDevice); + MidiDeviceInfo info = theDevice.getInfo(); + int deviceID = info.getId(); + + if (! openTasks.containsKey (deviceID)) + { + if (info.getType() == MidiDeviceInfo.TYPE_BLUETOOTH) + { + BluetoothDevice btDevice = (BluetoothDevice) info.getProperties().get (info.PROPERTY_BLUETOOTH_DEVICE); + if (btDevice != null) + { + String btAddress = btDevice.getAddress(); + if (btDevicesPairing.contains (btAddress)) + { + btDevicesPairing.remove (btAddress); + } + else + { + // unpair was called in the mean time + try + { + theDevice.close(); + } + catch (IOException e) + {} + + return; + } + } + } + + MidiDeviceOpenTask openTask = new MidiDeviceOpenTask (this, theDevice); + openTasks.put (deviceID, openTask); + + new java.util.Timer().schedule (openTask, 3000); + } + } + } + + public void onDeviceOpenedDelayed (MidiDevice theDevice) + { + synchronized (MidiDeviceManager.class) + { + int deviceID = theDevice.getInfo().getId(); + + if (openTasks.containsKey (deviceID)) + { + if (! midiDevices.contains(theDevice)) + { + openTasks.remove (deviceID); + midiDevices.add (theDevice); + } + } + else + { + // unpair was called in the mean time + try + { + theDevice.close(); + } + catch (IOException e) + {} + } } } @@ -808,6 +1003,8 @@ public class JuceDemoPlugin extends Activity } private MidiManager manager; + private HashSet btDevicesPairing; + private HashMap openTasks; private ArrayList midiDevices; private MidiDeviceInfo[] deviceInfos; private HashMap> openPorts; diff --git a/extras/AudioPerformanceTest/Builds/Android/app/src/main/java/com/juce/audioperformancetest/AudioPerformanceTest.java b/extras/AudioPerformanceTest/Builds/Android/app/src/main/java/com/juce/audioperformancetest/AudioPerformanceTest.java index 6007d14340..384eb01906 100644 --- a/extras/AudioPerformanceTest/Builds/Android/app/src/main/java/com/juce/audioperformancetest/AudioPerformanceTest.java +++ b/extras/AudioPerformanceTest/Builds/Android/app/src/main/java/com/juce/audioperformancetest/AudioPerformanceTest.java @@ -194,9 +194,9 @@ public class AudioPerformanceTest extends Activity return btDevice.getName(); } - public boolean isBluetoothDevicePaired (String address) + public int getBluetoothDeviceStatus (String address) { - return getAndroidMidiDeviceManager().isBluetoothDevicePaired (address); + return getAndroidMidiDeviceManager().getBluetoothDeviceStatus (address); } public void startStopScan (boolean shouldStart) @@ -487,7 +487,78 @@ public class AudioPerformanceTest extends Activity //============================================================================== public class MidiDeviceManager extends MidiManager.DeviceCallback implements MidiManager.OnDeviceOpenedListener { + //============================================================================== + private class MidiDeviceOpenTask extends java.util.TimerTask + { + public MidiDeviceOpenTask (MidiDeviceManager deviceManager, MidiDevice device) + { + owner = deviceManager; + midiDevice = device; + } + + @Override + public boolean cancel() + { + synchronized (MidiDeviceOpenTask.class) + { + owner = null; + boolean retval = super.cancel(); + + if (midiDevice != null) + { + try + { + midiDevice.close(); + } + catch (IOException e) + {} + + midiDevice = null; + } + + return retval; + } + } + + public String getBluetoothAddress() + { + synchronized (MidiDeviceOpenTask.class) + { + if (midiDevice != null) + { + MidiDeviceInfo info = midiDevice.getInfo(); + if (info.getType() == MidiDeviceInfo.TYPE_BLUETOOTH) + { + BluetoothDevice btDevice = (BluetoothDevice) info.getProperties().get (info.PROPERTY_BLUETOOTH_DEVICE); + if (btDevice != null) + return btDevice.getAddress(); + } + } + } + + return ""; + } + public int getID() + { + return midiDevice.getInfo().getId(); + } + + @Override + public void run() + { + synchronized (MidiDeviceOpenTask.class) + { + if (owner != null && midiDevice != null) + owner.onDeviceOpenedDelayed (midiDevice); + } + } + + private MidiDeviceManager owner; + private MidiDevice midiDevice; + } + + //============================================================================== public MidiDeviceManager() { manager = (MidiManager) getSystemService (MIDI_SERVICE); @@ -500,6 +571,8 @@ public class AudioPerformanceTest extends Activity openPorts = new HashMap> (); midiDevices = new ArrayList(); + openTasks = new HashMap(); + btDevicesPairing = new HashSet(); MidiDeviceInfo[] foundDevices = manager.getDevices(); for (MidiDeviceInfo info : foundDevices) @@ -512,6 +585,16 @@ public class AudioPerformanceTest extends Activity { manager.unregisterDeviceCallback (this); + synchronized (MidiDeviceManager.class) + { + btDevicesPairing.clear(); + + for (Integer deviceID : openTasks.keySet()) + openTasks.get (deviceID).cancel(); + + openTasks = null; + } + for (MidiPortPath key : openPorts.keySet()) openPorts.get (key).get().close(); @@ -606,21 +689,62 @@ public class AudioPerformanceTest extends Activity return openMidiPortWithJuceIndex (index, 0, false); } - public boolean isBluetoothDevicePaired (String address) + /* 0: unpaired, 1: paired, 2: pairing */ + public int getBluetoothDeviceStatus (String address) { - return (findMidiDeviceForBluetoothAddress (address) != null); + synchronized (MidiDeviceManager.class) + { + if (! address.isEmpty()) + { + if (findMidiDeviceForBluetoothAddress (address) != null) + return 1; + + if (btDevicesPairing.contains (address)) + return 2; + + if (findOpenTaskForBluetoothAddress (address) != null) + return 2; + } + } + + return 0; } public boolean pairBluetoothDevice (BluetoothDevice btDevice) { - manager.openBluetoothDevice(btDevice, this, null); + String btAddress = btDevice.getAddress(); + if (btAddress.isEmpty()) + return false; + + synchronized (MidiDeviceManager.class) + { + if (getBluetoothDeviceStatus (btAddress) != 0) + return false; + + btDevicesPairing.add (btDevice.getAddress()); + manager.openBluetoothDevice(btDevice, this, null); + } + return true; } public void unpairBluetoothDevice (String address) { + if (address.isEmpty()) + return; + synchronized (MidiDeviceManager.class) { + btDevicesPairing.remove (address); + + MidiDeviceOpenTask openTask = findOpenTaskForBluetoothAddress (address); + if (openTask != null) + { + int deviceID = openTask.getID(); + openTask.cancel(); + openTasks.remove (deviceID); + } + MidiDevice midiDevice = findMidiDeviceForBluetoothAddress (address); if (midiDevice != null) { @@ -653,6 +777,18 @@ public class AudioPerformanceTest extends Activity return null; } + private MidiDeviceOpenTask findOpenTaskForBluetoothAddress (String address) + { + for (Integer deviceID : openTasks.keySet()) + { + MidiDeviceOpenTask openTask = openTasks.get (deviceID); + if (openTask.getBluetoothAddress().equals (address)) + return openTask; + } + + return null; + } + public void removePort (MidiPortPath path) { openPorts.remove (path); @@ -719,9 +855,68 @@ public class AudioPerformanceTest extends Activity { synchronized (MidiDeviceManager.class) { - // make sure it's not already there - if (! midiDevices.contains(theDevice)) - midiDevices.add (theDevice); + MidiDeviceInfo info = theDevice.getInfo(); + int deviceID = info.getId(); + + if (! openTasks.containsKey (deviceID)) + { + if (info.getType() == MidiDeviceInfo.TYPE_BLUETOOTH) + { + BluetoothDevice btDevice = (BluetoothDevice) info.getProperties().get (info.PROPERTY_BLUETOOTH_DEVICE); + if (btDevice != null) + { + String btAddress = btDevice.getAddress(); + if (btDevicesPairing.contains (btAddress)) + { + btDevicesPairing.remove (btAddress); + } + else + { + // unpair was called in the mean time + try + { + theDevice.close(); + } + catch (IOException e) + {} + + return; + } + } + } + + MidiDeviceOpenTask openTask = new MidiDeviceOpenTask (this, theDevice); + openTasks.put (deviceID, openTask); + + new java.util.Timer().schedule (openTask, 3000); + } + } + } + + public void onDeviceOpenedDelayed (MidiDevice theDevice) + { + synchronized (MidiDeviceManager.class) + { + int deviceID = theDevice.getInfo().getId(); + + if (openTasks.containsKey (deviceID)) + { + if (! midiDevices.contains(theDevice)) + { + openTasks.remove (deviceID); + midiDevices.add (theDevice); + } + } + else + { + // unpair was called in the mean time + try + { + theDevice.close(); + } + catch (IOException e) + {} + } } } @@ -808,6 +1003,8 @@ public class AudioPerformanceTest extends Activity } private MidiManager manager; + private HashSet btDevicesPairing; + private HashMap openTasks; private ArrayList midiDevices; private MidiDeviceInfo[] deviceInfos; private HashMap> openPorts; diff --git a/modules/juce_audio_utils/native/juce_android_BluetoothMidiDevicePairingDialogue.cpp b/modules/juce_audio_utils/native/juce_android_BluetoothMidiDevicePairingDialogue.cpp index 17c89f44cd..e3601fe749 100644 --- a/modules/juce_audio_utils/native/juce_android_BluetoothMidiDevicePairingDialogue.cpp +++ b/modules/juce_audio_utils/native/juce_android_BluetoothMidiDevicePairingDialogue.cpp @@ -28,7 +28,7 @@ METHOD (pairBluetoothMidiDevice, "pairBluetoothMidiDevice", "(Ljava/lang/String;)Z") \ METHOD (unpairBluetoothMidiDevice, "unpairBluetoothMidiDevice", "(Ljava/lang/String;)V") \ METHOD (getHumanReadableStringForBluetoothAddress, "getHumanReadableStringForBluetoothAddress", "(Ljava/lang/String;)Ljava/lang/String;") \ - METHOD (isBluetoothDevicePaired, "isBluetoothDevicePaired", "(Ljava/lang/String;)Z") \ + METHOD (getBluetoothDeviceStatus, "getBluetoothDeviceStatus", "(Ljava/lang/String;)I") \ METHOD (startStopScan, "startStopScan", "(Z)V") DECLARE_JNI_CLASS (AndroidBluetoothManager, JUCE_ANDROID_ACTIVITY_CLASSPATH "$BluetoothManager"); @@ -121,17 +121,24 @@ struct AndroidBluetoothMidiInterface } //============================================================================== - static bool isBluetoothDevicePaired (const String& address) + enum PairStatus + { + unpaired = 0, + paired = 1, + pairing = 2 + }; + + static PairStatus isBluetoothDevicePaired (const String& address) { JNIEnv* env = getEnv(); LocalRef btManager (android.activity.callObjectMethod (JuceAppActivity.getAndroidBluetoothManager)); if (btManager.get() == nullptr) - return false; + return unpaired; - return env->CallBooleanMethod (btManager.get(), AndroidBluetoothManager.isBluetoothDevicePaired, - javaString (address).get()); + return static_cast (env->CallIntMethod (btManager.get(), AndroidBluetoothManager.getBluetoothDeviceStatus, + javaString (address).get())); } }; @@ -350,9 +357,19 @@ private: address != bluetoothAddresses.end(); ++address) { String name = AndroidBluetoothMidiInterface::getHumanReadableStringForBluetoothAddress (*address); - DeviceStatus status = AndroidBluetoothMidiInterface::isBluetoothDevicePaired (*address) - ? AndroidBluetoothMidiDevice::connected - : AndroidBluetoothMidiDevice::disconnected; + + DeviceStatus status; + switch (AndroidBluetoothMidiInterface::isBluetoothDevicePaired (*address)) + { + case AndroidBluetoothMidiInterface::pairing: + status = AndroidBluetoothMidiDevice::connecting; + break; + case AndroidBluetoothMidiInterface::paired: + status = AndroidBluetoothMidiDevice::connected; + break; + default: + status = AndroidBluetoothMidiDevice::disconnected; + } newDevices.add (AndroidBluetoothMidiDevice (name, *address, status)); } diff --git a/modules/juce_core/native/java/AndroidMidi.java b/modules/juce_core/native/java/AndroidMidi.java index 911d9ba47f..1eeb337a7f 100644 --- a/modules/juce_core/native/java/AndroidMidi.java +++ b/modules/juce_core/native/java/AndroidMidi.java @@ -16,9 +16,9 @@ return btDevice.getName(); } - public boolean isBluetoothDevicePaired (String address) + public int getBluetoothDeviceStatus (String address) { - return getAndroidMidiDeviceManager().isBluetoothDevicePaired (address); + return getAndroidMidiDeviceManager().getBluetoothDeviceStatus (address); } public void startStopScan (boolean shouldStart) @@ -309,7 +309,78 @@ //============================================================================== public class MidiDeviceManager extends MidiManager.DeviceCallback implements MidiManager.OnDeviceOpenedListener { + //============================================================================== + private class MidiDeviceOpenTask extends java.util.TimerTask + { + public MidiDeviceOpenTask (MidiDeviceManager deviceManager, MidiDevice device) + { + owner = deviceManager; + midiDevice = device; + } + + @Override + public boolean cancel() + { + synchronized (MidiDeviceOpenTask.class) + { + owner = null; + boolean retval = super.cancel(); + + if (midiDevice != null) + { + try + { + midiDevice.close(); + } + catch (IOException e) + {} + + midiDevice = null; + } + + return retval; + } + } + + public String getBluetoothAddress() + { + synchronized (MidiDeviceOpenTask.class) + { + if (midiDevice != null) + { + MidiDeviceInfo info = midiDevice.getInfo(); + if (info.getType() == MidiDeviceInfo.TYPE_BLUETOOTH) + { + BluetoothDevice btDevice = (BluetoothDevice) info.getProperties().get (info.PROPERTY_BLUETOOTH_DEVICE); + if (btDevice != null) + return btDevice.getAddress(); + } + } + } + + return ""; + } + public int getID() + { + return midiDevice.getInfo().getId(); + } + + @Override + public void run() + { + synchronized (MidiDeviceOpenTask.class) + { + if (owner != null && midiDevice != null) + owner.onDeviceOpenedDelayed (midiDevice); + } + } + + private MidiDeviceManager owner; + private MidiDevice midiDevice; + } + + //============================================================================== public MidiDeviceManager() { manager = (MidiManager) getSystemService (MIDI_SERVICE); @@ -322,6 +393,8 @@ openPorts = new HashMap> (); midiDevices = new ArrayList(); + openTasks = new HashMap(); + btDevicesPairing = new HashSet(); MidiDeviceInfo[] foundDevices = manager.getDevices(); for (MidiDeviceInfo info : foundDevices) @@ -334,6 +407,16 @@ { manager.unregisterDeviceCallback (this); + synchronized (MidiDeviceManager.class) + { + btDevicesPairing.clear(); + + for (Integer deviceID : openTasks.keySet()) + openTasks.get (deviceID).cancel(); + + openTasks = null; + } + for (MidiPortPath key : openPorts.keySet()) openPorts.get (key).get().close(); @@ -428,21 +511,62 @@ return openMidiPortWithJuceIndex (index, 0, false); } - public boolean isBluetoothDevicePaired (String address) + /* 0: unpaired, 1: paired, 2: pairing */ + public int getBluetoothDeviceStatus (String address) { - return (findMidiDeviceForBluetoothAddress (address) != null); + synchronized (MidiDeviceManager.class) + { + if (! address.isEmpty()) + { + if (findMidiDeviceForBluetoothAddress (address) != null) + return 1; + + if (btDevicesPairing.contains (address)) + return 2; + + if (findOpenTaskForBluetoothAddress (address) != null) + return 2; + } + } + + return 0; } public boolean pairBluetoothDevice (BluetoothDevice btDevice) { - manager.openBluetoothDevice(btDevice, this, null); + String btAddress = btDevice.getAddress(); + if (btAddress.isEmpty()) + return false; + + synchronized (MidiDeviceManager.class) + { + if (getBluetoothDeviceStatus (btAddress) != 0) + return false; + + btDevicesPairing.add (btDevice.getAddress()); + manager.openBluetoothDevice(btDevice, this, null); + } + return true; } public void unpairBluetoothDevice (String address) { + if (address.isEmpty()) + return; + synchronized (MidiDeviceManager.class) { + btDevicesPairing.remove (address); + + MidiDeviceOpenTask openTask = findOpenTaskForBluetoothAddress (address); + if (openTask != null) + { + int deviceID = openTask.getID(); + openTask.cancel(); + openTasks.remove (deviceID); + } + MidiDevice midiDevice = findMidiDeviceForBluetoothAddress (address); if (midiDevice != null) { @@ -475,6 +599,18 @@ return null; } + private MidiDeviceOpenTask findOpenTaskForBluetoothAddress (String address) + { + for (Integer deviceID : openTasks.keySet()) + { + MidiDeviceOpenTask openTask = openTasks.get (deviceID); + if (openTask.getBluetoothAddress().equals (address)) + return openTask; + } + + return null; + } + public void removePort (MidiPortPath path) { openPorts.remove (path); @@ -541,9 +677,68 @@ { synchronized (MidiDeviceManager.class) { - // make sure it's not already there - if (! midiDevices.contains(theDevice)) - midiDevices.add (theDevice); + MidiDeviceInfo info = theDevice.getInfo(); + int deviceID = info.getId(); + + if (! openTasks.containsKey (deviceID)) + { + if (info.getType() == MidiDeviceInfo.TYPE_BLUETOOTH) + { + BluetoothDevice btDevice = (BluetoothDevice) info.getProperties().get (info.PROPERTY_BLUETOOTH_DEVICE); + if (btDevice != null) + { + String btAddress = btDevice.getAddress(); + if (btDevicesPairing.contains (btAddress)) + { + btDevicesPairing.remove (btAddress); + } + else + { + // unpair was called in the mean time + try + { + theDevice.close(); + } + catch (IOException e) + {} + + return; + } + } + } + + MidiDeviceOpenTask openTask = new MidiDeviceOpenTask (this, theDevice); + openTasks.put (deviceID, openTask); + + new java.util.Timer().schedule (openTask, 3000); + } + } + } + + public void onDeviceOpenedDelayed (MidiDevice theDevice) + { + synchronized (MidiDeviceManager.class) + { + int deviceID = theDevice.getInfo().getId(); + + if (openTasks.containsKey (deviceID)) + { + if (! midiDevices.contains(theDevice)) + { + openTasks.remove (deviceID); + midiDevices.add (theDevice); + } + } + else + { + // unpair was called in the mean time + try + { + theDevice.close(); + } + catch (IOException e) + {} + } } } @@ -630,6 +825,8 @@ } private MidiManager manager; + private HashSet btDevicesPairing; + private HashMap openTasks; private ArrayList midiDevices; private MidiDeviceInfo[] deviceInfos; private HashMap> openPorts; diff --git a/modules/juce_core/native/java/AndroidMidiFallback.java b/modules/juce_core/native/java/AndroidMidiFallback.java index ff04f3099e..5e3d57ff4e 100644 --- a/modules/juce_core/native/java/AndroidMidiFallback.java +++ b/modules/juce_core/native/java/AndroidMidiFallback.java @@ -16,9 +16,9 @@ return address; } - public boolean isBluetoothDevicePaired (String address) + public int getBluetoothDeviceStatus (String address) { - return false; + return 0; } public void startStopScan (boolean shouldStart)