AndroidMidi.java 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836
  1. //==============================================================================
  2. public class BluetoothManager extends ScanCallback
  3. {
  4. BluetoothManager()
  5. {
  6. ScanFilter.Builder scanFilterBuilder = new ScanFilter.Builder();
  7. scanFilterBuilder.setServiceUuid (ParcelUuid.fromString (bluetoothLEMidiServiceUUID));
  8. ScanSettings.Builder scanSettingsBuilder = new ScanSettings.Builder();
  9. scanSettingsBuilder.setCallbackType (ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
  10. .setScanMode (ScanSettings.SCAN_MODE_LOW_POWER)
  11. .setScanMode (ScanSettings.MATCH_MODE_STICKY);
  12. BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
  13. if (bluetoothAdapter == null)
  14. {
  15. Log.d ("JUCE", "BluetoothManager error: could not get default Bluetooth adapter");
  16. return;
  17. }
  18. BluetoothLeScanner bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
  19. if (bluetoothLeScanner == null)
  20. {
  21. Log.d ("JUCE", "BluetoothManager error: could not get Bluetooth LE scanner");
  22. return;
  23. }
  24. bluetoothLeScanner.startScan (Arrays.asList (scanFilterBuilder.build()),
  25. scanSettingsBuilder.build(),
  26. this);
  27. }
  28. public String[] getMidiBluetoothAddresses()
  29. {
  30. return bluetoothMidiDevices.toArray (new String[bluetoothMidiDevices.size()]);
  31. }
  32. public String getHumanReadableStringForBluetoothAddress (String address)
  33. {
  34. BluetoothDevice btDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice (address);
  35. return btDevice.getName();
  36. }
  37. public boolean isBluetoothDevicePaired (String address)
  38. {
  39. return getAndroidMidiDeviceManager().isBluetoothDevicePaired (address);
  40. }
  41. public boolean pairBluetoothMidiDevice(String address)
  42. {
  43. BluetoothDevice btDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice (address);
  44. if (btDevice == null)
  45. {
  46. Log.d ("JUCE", "failed to create buletooth device from address");
  47. return false;
  48. }
  49. MidiManager mm = (MidiManager) getSystemService (MIDI_SERVICE);
  50. PhysicalMidiDevice midiDevice = PhysicalMidiDevice.fromBluetoothLeDevice (btDevice, mm);
  51. if (midiDevice != null)
  52. {
  53. getAndroidMidiDeviceManager().addDeviceToList (midiDevice);
  54. return true;
  55. }
  56. return false;
  57. }
  58. public void unpairBluetoothMidiDevice (String address)
  59. {
  60. getAndroidMidiDeviceManager().unpairBluetoothDevice (address);
  61. }
  62. public void onScanFailed (int errorCode)
  63. {
  64. }
  65. public void onScanResult (int callbackType, ScanResult result)
  66. {
  67. if (callbackType == ScanSettings.CALLBACK_TYPE_ALL_MATCHES
  68. || callbackType == ScanSettings.CALLBACK_TYPE_FIRST_MATCH)
  69. {
  70. BluetoothDevice device = result.getDevice();
  71. if (device != null)
  72. bluetoothMidiDevices.add (device.getAddress());
  73. }
  74. if (callbackType == ScanSettings.CALLBACK_TYPE_MATCH_LOST)
  75. {
  76. Log.d ("JUCE", "ScanSettings.CALLBACK_TYPE_MATCH_LOST");
  77. BluetoothDevice device = result.getDevice();
  78. if (device != null)
  79. {
  80. bluetoothMidiDevices.remove (device.getAddress());
  81. unpairBluetoothMidiDevice (device.getAddress());
  82. }
  83. }
  84. }
  85. public void onBatchScanResults (List<ScanResult> results)
  86. {
  87. for (ScanResult result : results)
  88. onScanResult (ScanSettings.CALLBACK_TYPE_ALL_MATCHES, result);
  89. }
  90. private BluetoothLeScanner scanner;
  91. private static final String bluetoothLEMidiServiceUUID = "03B80E5A-EDE8-4B33-A751-6CE34EC4C700";
  92. private HashSet<String> bluetoothMidiDevices = new HashSet<String>();
  93. }
  94. public static class JuceMidiInputPort extends MidiReceiver implements JuceMidiPort
  95. {
  96. private native void handleReceive (long host, byte[] msg, int offset, int count, long timestamp);
  97. public JuceMidiInputPort (PhysicalMidiDevice device, long host, MidiOutputPort midiPort)
  98. {
  99. parent = device;
  100. juceHost = host;
  101. port = midiPort;
  102. }
  103. @Override
  104. public boolean isInputPort()
  105. {
  106. return true;
  107. }
  108. @Override
  109. public void start()
  110. {
  111. port.connect (this);
  112. }
  113. @Override
  114. public void stop()
  115. {
  116. port.disconnect (this);
  117. }
  118. @Override
  119. public void close()
  120. {
  121. stop();
  122. try
  123. {
  124. port.close();
  125. }
  126. catch (IOException e)
  127. {
  128. Log.d ("JUCE", "JuceMidiInputPort::close: IOException = " + e.toString());
  129. }
  130. if (parent != null)
  131. {
  132. parent.removePort (port.getPortNumber(), true);
  133. parent = null;
  134. }
  135. }
  136. public void onSend (byte[] msg, int offset, int count, long timestamp)
  137. {
  138. if (count > 0)
  139. handleReceive (juceHost, msg, offset, count, timestamp);
  140. }
  141. @Override
  142. public MidiPortID getPortId()
  143. {
  144. return new MidiPortID (port.getPortNumber(), true);
  145. }
  146. @Override
  147. public void sendMidi (byte[] msg, int offset, int count)
  148. {
  149. }
  150. private PhysicalMidiDevice parent = null;
  151. private long juceHost = 0;
  152. private MidiOutputPort port;
  153. }
  154. public static class JuceMidiOutputPort implements JuceMidiPort
  155. {
  156. public JuceMidiOutputPort (PhysicalMidiDevice device, MidiInputPort midiPort)
  157. {
  158. parent = device;
  159. port = midiPort;
  160. }
  161. @Override
  162. public boolean isInputPort()
  163. {
  164. return false;
  165. }
  166. @Override
  167. public void start()
  168. {
  169. }
  170. @Override
  171. public void stop()
  172. {
  173. }
  174. @Override
  175. public void sendMidi (byte[] msg, int offset, int count)
  176. {
  177. try
  178. {
  179. port.send(msg, offset, count);
  180. }
  181. catch (IOException e)
  182. {
  183. Log.d ("JUCE", "JuceMidiOutputPort::sendMidi: IOException = " + e.toString());
  184. }
  185. }
  186. @Override
  187. public void close()
  188. {
  189. try
  190. {
  191. port.close();
  192. }
  193. catch (IOException e)
  194. {
  195. Log.d ("JUCE", "JuceMidiOutputPort::close: IOException = " + e.toString());
  196. }
  197. if (parent != null)
  198. {
  199. parent.removePort (port.getPortNumber(), false);
  200. parent = null;
  201. }
  202. }
  203. @Override
  204. public MidiPortID getPortId()
  205. {
  206. return new MidiPortID (port.getPortNumber(), false);
  207. }
  208. private PhysicalMidiDevice parent = null;
  209. private MidiInputPort port;
  210. }
  211. public static class PhysicalMidiDevice
  212. {
  213. private static class MidiDeviceThread extends Thread
  214. {
  215. public Handler handler = null;
  216. public Object sync = null;
  217. public MidiDeviceThread (Object syncrhonization)
  218. {
  219. sync = syncrhonization;
  220. }
  221. public void run()
  222. {
  223. Looper.prepare();
  224. synchronized (sync)
  225. {
  226. handler = new Handler();
  227. sync.notifyAll();
  228. }
  229. Looper.loop();
  230. }
  231. }
  232. private static class MidiDeviceOpenCallback implements MidiManager.OnDeviceOpenedListener
  233. {
  234. public Object sync = null;
  235. public boolean isWaiting = true;
  236. public android.media.midi.MidiDevice theDevice = null;
  237. public MidiDeviceOpenCallback (Object waiter)
  238. {
  239. sync = waiter;
  240. }
  241. public void onDeviceOpened (MidiDevice device)
  242. {
  243. synchronized (sync)
  244. {
  245. theDevice = device;
  246. isWaiting = false;
  247. sync.notifyAll();
  248. }
  249. }
  250. }
  251. public static PhysicalMidiDevice fromBluetoothLeDevice (BluetoothDevice bluetoothDevice, MidiManager mm)
  252. {
  253. Object waitForCreation = new Object();
  254. MidiDeviceThread thread = new MidiDeviceThread (waitForCreation);
  255. thread.start();
  256. synchronized (waitForCreation)
  257. {
  258. while (thread.handler == null)
  259. {
  260. try
  261. {
  262. waitForCreation.wait();
  263. }
  264. catch (InterruptedException e)
  265. {
  266. Log.d ("JUCE", "Wait was interrupted but we don't care");
  267. }
  268. }
  269. }
  270. Object waitForDevice = new Object();
  271. MidiDeviceOpenCallback openCallback = new MidiDeviceOpenCallback (waitForDevice);
  272. synchronized (waitForDevice)
  273. {
  274. mm.openBluetoothDevice (bluetoothDevice, openCallback, thread.handler);
  275. while (openCallback.isWaiting)
  276. {
  277. try
  278. {
  279. waitForDevice.wait();
  280. }
  281. catch (InterruptedException e)
  282. {
  283. Log.d ("JUCE", "Wait was interrupted but we don't care");
  284. }
  285. }
  286. }
  287. if (openCallback.theDevice == null)
  288. {
  289. Log.d ("JUCE", "openBluetoothDevice failed");
  290. return null;
  291. }
  292. PhysicalMidiDevice device = new PhysicalMidiDevice();
  293. device.handle = openCallback.theDevice;
  294. device.info = device.handle.getInfo();
  295. device.bluetoothAddress = bluetoothDevice.getAddress();
  296. device.midiManager = mm;
  297. return device;
  298. }
  299. public void unpair()
  300. {
  301. if (! bluetoothAddress.equals ("") && handle != null)
  302. {
  303. JuceMidiPort ports[] = new JuceMidiPort[0];
  304. ports = juceOpenedPorts.values().toArray(ports);
  305. for (int i = 0; i < ports.length; ++i)
  306. ports[i].close();
  307. juceOpenedPorts.clear();
  308. try
  309. {
  310. handle.close();
  311. }
  312. catch (IOException e)
  313. {
  314. Log.d ("JUCE", "handle.close(): IOException = " + e.toString());
  315. }
  316. handle = null;
  317. }
  318. }
  319. public static PhysicalMidiDevice fromMidiDeviceInfo (MidiDeviceInfo info, MidiManager mm)
  320. {
  321. PhysicalMidiDevice device = new PhysicalMidiDevice();
  322. device.info = info;
  323. device.midiManager = mm;
  324. return device;
  325. }
  326. public PhysicalMidiDevice()
  327. {
  328. bluetoothAddress = "";
  329. juceOpenedPorts = new Hashtable<MidiPortID, JuceMidiPort>();
  330. handle = null;
  331. }
  332. public MidiDeviceInfo.PortInfo[] getPorts()
  333. {
  334. return info.getPorts();
  335. }
  336. public String getHumanReadableNameForPort (MidiDeviceInfo.PortInfo port, int portIndexToUseInName)
  337. {
  338. String portName = port.getName();
  339. if (portName.equals (""))
  340. portName = ((port.getType() == MidiDeviceInfo.PortInfo.TYPE_OUTPUT) ? "Out " : "In ")
  341. + Integer.toString (portIndexToUseInName);
  342. return getHumanReadableDeviceName() + " " + portName;
  343. }
  344. public String getHumanReadableNameForPort (int portType, int androidPortID, int portIndexToUseInName)
  345. {
  346. MidiDeviceInfo.PortInfo[] ports = info.getPorts();
  347. for (MidiDeviceInfo.PortInfo port : ports)
  348. {
  349. if (port.getType() == portType)
  350. {
  351. if (port.getPortNumber() == androidPortID)
  352. return getHumanReadableNameForPort (port, portIndexToUseInName);
  353. }
  354. }
  355. return "Unknown";
  356. }
  357. public String getHumanReadableDeviceName()
  358. {
  359. Bundle bundle = info.getProperties();
  360. return bundle.getString (MidiDeviceInfo.PROPERTY_NAME , "Unknown device");
  361. }
  362. public void checkIfDeviceCanBeClosed()
  363. {
  364. if (juceOpenedPorts.size() == 0)
  365. {
  366. // never close bluetooth LE devices, otherwise they unpair and we have
  367. // no idea how many ports they have.
  368. // Only remove bluetooth devices when we specifically unpair
  369. if (bluetoothAddress.equals (""))
  370. {
  371. try
  372. {
  373. handle.close();
  374. handle = null;
  375. }
  376. catch (IOException e)
  377. {
  378. Log.d ("JUCE", "PhysicalMidiDevice::checkIfDeviceCanBeClosed: IOException = " + e.toString());
  379. }
  380. }
  381. }
  382. }
  383. public void removePort (int portIdx, boolean isInput)
  384. {
  385. MidiPortID portID = new MidiPortID (portIdx, isInput);
  386. JuceMidiPort port = juceOpenedPorts.get (portID);
  387. if (port != null)
  388. {
  389. juceOpenedPorts.remove (portID);
  390. checkIfDeviceCanBeClosed();
  391. return;
  392. }
  393. // tried to remove a port that was never added
  394. assert false;
  395. }
  396. public JuceMidiPort openPort (int portIdx, boolean isInput, long host)
  397. {
  398. open();
  399. if (handle == null)
  400. {
  401. Log.d ("JUCE", "PhysicalMidiDevice::openPort: handle = null, device not open");
  402. return null;
  403. }
  404. // make sure that the port is not already open
  405. if (findPortForIdx (portIdx, isInput) != null)
  406. {
  407. Log.d ("JUCE", "PhysicalMidiDevice::openInputPort: port already open, not opening again!");
  408. return null;
  409. }
  410. JuceMidiPort retval = null;
  411. if (isInput)
  412. {
  413. MidiOutputPort androidPort = handle.openOutputPort (portIdx);
  414. if (androidPort == null)
  415. {
  416. Log.d ("JUCE", "PhysicalMidiDevice::openPort: MidiDevice::openOutputPort (portIdx = "
  417. + Integer.toString (portIdx) + ") failed!");
  418. return null;
  419. }
  420. retval = new JuceMidiInputPort (this, host, androidPort);
  421. }
  422. else
  423. {
  424. MidiInputPort androidPort = handle.openInputPort (portIdx);
  425. if (androidPort == null)
  426. {
  427. Log.d ("JUCE", "PhysicalMidiDevice::openPort: MidiDevice::openInputPort (portIdx = "
  428. + Integer.toString (portIdx) + ") failed!");
  429. return null;
  430. }
  431. retval = new JuceMidiOutputPort (this, androidPort);
  432. }
  433. juceOpenedPorts.put (new MidiPortID (portIdx, isInput), retval);
  434. return retval;
  435. }
  436. private JuceMidiPort findPortForIdx (int idx, boolean isInput)
  437. {
  438. return juceOpenedPorts.get (new MidiPortID (idx, isInput));
  439. }
  440. // opens the device
  441. private synchronized void open()
  442. {
  443. if (handle != null)
  444. return;
  445. Object waitForCreation = new Object();
  446. MidiDeviceThread thread = new MidiDeviceThread (waitForCreation);
  447. thread.start();
  448. synchronized(waitForCreation)
  449. {
  450. while (thread.handler == null)
  451. {
  452. try
  453. {
  454. waitForCreation.wait();
  455. }
  456. catch (InterruptedException e)
  457. {
  458. Log.d ("JUCE", "wait was interrupted but we don't care");
  459. }
  460. }
  461. }
  462. Object waitForDevice = new Object();
  463. MidiDeviceOpenCallback openCallback = new MidiDeviceOpenCallback (waitForDevice);
  464. synchronized (waitForDevice)
  465. {
  466. midiManager.openDevice (info, openCallback, thread.handler);
  467. while (openCallback.isWaiting)
  468. {
  469. try
  470. {
  471. waitForDevice.wait();
  472. }
  473. catch (InterruptedException e)
  474. {
  475. Log.d ("JUCE", "wait was interrupted but we don't care");
  476. }
  477. }
  478. }
  479. handle = openCallback.theDevice;
  480. }
  481. private MidiDeviceInfo info;
  482. private Hashtable<MidiPortID, JuceMidiPort> juceOpenedPorts;
  483. public MidiDevice handle;
  484. public String bluetoothAddress;
  485. private MidiManager midiManager;
  486. }
  487. //==============================================================================
  488. public class MidiDeviceManager extends MidiManager.DeviceCallback
  489. {
  490. public class MidiPortPath
  491. {
  492. public PhysicalMidiDevice midiDevice;
  493. public int androidMidiPortID;
  494. public int portIndexToUseInName;
  495. }
  496. public class JuceDeviceList
  497. {
  498. public ArrayList<MidiPortPath> inPorts = new ArrayList<MidiPortPath>();
  499. public ArrayList<MidiPortPath> outPorts = new ArrayList<MidiPortPath>();
  500. }
  501. // We need to keep a thread local copy of the devices
  502. // which we returned the last time
  503. // getJuceAndroidMidiIn/OutputDevices() was called
  504. private final ThreadLocal<JuceDeviceList> lastDevicesReturned =
  505. new ThreadLocal<JuceDeviceList>()
  506. {
  507. @Override protected JuceDeviceList initialValue()
  508. {
  509. return new JuceDeviceList();
  510. }
  511. };
  512. public MidiDeviceManager()
  513. {
  514. physicalMidiDevices = new ArrayList<PhysicalMidiDevice>();
  515. manager = (MidiManager) getSystemService (MIDI_SERVICE);
  516. if (manager == null)
  517. {
  518. Log.d ("JUCE", "MidiDeviceManager error: could not get MidiManager system service");
  519. return;
  520. }
  521. manager.registerDeviceCallback (this, null);
  522. MidiDeviceInfo[] foundDevices = manager.getDevices();
  523. for (MidiDeviceInfo info : foundDevices)
  524. physicalMidiDevices.add (PhysicalMidiDevice.fromMidiDeviceInfo (info, manager));
  525. }
  526. // specifically add a device to the list
  527. public void addDeviceToList (PhysicalMidiDevice device)
  528. {
  529. physicalMidiDevices.add (device);
  530. }
  531. public void unpairBluetoothDevice (String address)
  532. {
  533. for (int i = 0; i < physicalMidiDevices.size(); ++i)
  534. {
  535. PhysicalMidiDevice device = physicalMidiDevices.get(i);
  536. if (device.bluetoothAddress.equals (address))
  537. {
  538. physicalMidiDevices.remove (i);
  539. device.unpair();
  540. return;
  541. }
  542. }
  543. }
  544. public boolean isBluetoothDevicePaired (String address)
  545. {
  546. for (int i = 0; i < physicalMidiDevices.size(); ++i)
  547. {
  548. PhysicalMidiDevice device = physicalMidiDevices.get(i);
  549. if (device.bluetoothAddress.equals (address))
  550. return true;
  551. }
  552. return false;
  553. }
  554. public String[] getJuceAndroidMidiInputDevices()
  555. {
  556. return getJuceAndroidMidiDevices (MidiDeviceInfo.PortInfo.TYPE_INPUT);
  557. }
  558. public String[] getJuceAndroidMidiOutputDevices()
  559. {
  560. return getJuceAndroidMidiDevices (MidiDeviceInfo.PortInfo.TYPE_OUTPUT);
  561. }
  562. private String[] getJuceAndroidMidiDevices (int portType)
  563. {
  564. ArrayList<MidiPortPath> listOfReturnedDevices = new ArrayList<MidiPortPath>();
  565. List<String> deviceNames = new ArrayList<String>();
  566. for (PhysicalMidiDevice physicalMidiDevice : physicalMidiDevices)
  567. {
  568. int portIdx = 0;
  569. MidiDeviceInfo.PortInfo[] ports = physicalMidiDevice.getPorts();
  570. for (MidiDeviceInfo.PortInfo port : ports)
  571. {
  572. if (port.getType() == portType)
  573. {
  574. MidiPortPath path = new MidiPortPath();
  575. path.midiDevice = physicalMidiDevice;
  576. path.androidMidiPortID = port.getPortNumber();
  577. path.portIndexToUseInName = ++portIdx;
  578. listOfReturnedDevices.add (path);
  579. deviceNames.add (physicalMidiDevice.getHumanReadableNameForPort (port,
  580. path.portIndexToUseInName));
  581. }
  582. }
  583. }
  584. String[] deviceNamesArray = new String[deviceNames.size()];
  585. if (portType == MidiDeviceInfo.PortInfo.TYPE_INPUT)
  586. {
  587. lastDevicesReturned.get().inPorts.clear();
  588. lastDevicesReturned.get().inPorts.addAll (listOfReturnedDevices);
  589. }
  590. else
  591. {
  592. lastDevicesReturned.get().outPorts.clear();
  593. lastDevicesReturned.get().outPorts.addAll (listOfReturnedDevices);
  594. }
  595. return deviceNames.toArray(deviceNamesArray);
  596. }
  597. public JuceMidiPort openMidiInputPortWithJuceIndex (int index, long host)
  598. {
  599. ArrayList<MidiPortPath> lastDevices = lastDevicesReturned.get().inPorts;
  600. if (index >= lastDevices.size() || index < 0)
  601. return null;
  602. MidiPortPath path = lastDevices.get (index);
  603. return path.midiDevice.openPort (path.androidMidiPortID, true, host);
  604. }
  605. public JuceMidiPort openMidiOutputPortWithJuceIndex (int index)
  606. {
  607. ArrayList<MidiPortPath> lastDevices = lastDevicesReturned.get().outPorts;
  608. if (index >= lastDevices.size() || index < 0)
  609. return null;
  610. MidiPortPath path = lastDevices.get (index);
  611. return path.midiDevice.openPort (path.androidMidiPortID, false, 0);
  612. }
  613. public String getInputPortNameForJuceIndex (int index)
  614. {
  615. ArrayList<MidiPortPath> lastDevices = lastDevicesReturned.get().inPorts;
  616. if (index >= lastDevices.size() || index < 0)
  617. return "";
  618. MidiPortPath path = lastDevices.get (index);
  619. return path.midiDevice.getHumanReadableNameForPort (MidiDeviceInfo.PortInfo.TYPE_INPUT,
  620. path.androidMidiPortID,
  621. path.portIndexToUseInName);
  622. }
  623. public String getOutputPortNameForJuceIndex (int index)
  624. {
  625. ArrayList<MidiPortPath> lastDevices = lastDevicesReturned.get().outPorts;
  626. if (index >= lastDevices.size() || index < 0)
  627. return "";
  628. MidiPortPath path = lastDevices.get (index);
  629. return path.midiDevice.getHumanReadableNameForPort (MidiDeviceInfo.PortInfo.TYPE_OUTPUT,
  630. path.androidMidiPortID,
  631. path.portIndexToUseInName);
  632. }
  633. public void onDeviceAdded (MidiDeviceInfo info)
  634. {
  635. PhysicalMidiDevice device = PhysicalMidiDevice.fromMidiDeviceInfo (info, manager);
  636. // Do not add bluetooth devices as they are already added by the native bluetooth dialog
  637. if (info.getType() != MidiDeviceInfo.TYPE_BLUETOOTH)
  638. physicalMidiDevices.add (device);
  639. }
  640. public void onDeviceRemoved (MidiDeviceInfo info)
  641. {
  642. for (int i = 0; i < physicalMidiDevices.size(); ++i)
  643. {
  644. if (physicalMidiDevices.get(i).info.getId() == info.getId())
  645. {
  646. physicalMidiDevices.remove (i);
  647. return;
  648. }
  649. }
  650. // Don't assert here as this may be called again after a bluetooth device is unpaired
  651. }
  652. public void onDeviceStatusChanged (MidiDeviceStatus status)
  653. {
  654. }
  655. private ArrayList<PhysicalMidiDevice> physicalMidiDevices;
  656. private MidiManager manager;
  657. }
  658. public MidiDeviceManager getAndroidMidiDeviceManager()
  659. {
  660. if (getSystemService (MIDI_SERVICE) == null)
  661. return null;
  662. synchronized (JuceAppActivity.class)
  663. {
  664. if (midiDeviceManager == null)
  665. midiDeviceManager = new MidiDeviceManager();
  666. }
  667. return midiDeviceManager;
  668. }
  669. public BluetoothManager getAndroidBluetoothManager()
  670. {
  671. BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
  672. if (adapter == null)
  673. return null;
  674. if (adapter.getBluetoothLeScanner() == null)
  675. return null;
  676. synchronized (JuceAppActivity.class)
  677. {
  678. if (bluetoothManager == null)
  679. bluetoothManager = new BluetoothManager();
  680. }
  681. return bluetoothManager;
  682. }