diff options
Diffstat (limited to 'java')
-rw-r--r-- | java/CMakeLists.txt | 3 | ||||
-rw-r--r-- | java/direct_bt/tinyb/Adapter.java | 417 | ||||
-rw-r--r-- | java/direct_bt/tinyb/DBTEvent.java (renamed from java/tinyb/hci/HCIEvent.java) | 10 | ||||
-rw-r--r-- | java/direct_bt/tinyb/DBTObject.java (renamed from java/tinyb/hci/HCIObject.java) | 31 | ||||
-rw-r--r-- | java/direct_bt/tinyb/Device.java (renamed from java/tinyb/hci/HCIDevice.java) | 64 | ||||
-rw-r--r-- | java/direct_bt/tinyb/GattCharacteristic.java (renamed from java/tinyb/hci/HCIGattCharacteristic.java) | 28 | ||||
-rw-r--r-- | java/direct_bt/tinyb/GattDescriptor.java (renamed from java/tinyb/hci/HCIGattDescriptor.java) | 25 | ||||
-rw-r--r-- | java/direct_bt/tinyb/GattService.java (renamed from java/tinyb/hci/HCIGattService.java) | 30 | ||||
-rw-r--r-- | java/direct_bt/tinyb/Manager.java (renamed from java/tinyb/hci/HCIManager.java) | 48 | ||||
-rw-r--r-- | java/direct_bt/tinyb/NativeDownlink.java | 87 | ||||
-rw-r--r-- | java/jni/BluetoothUtils.cxx | 53 | ||||
-rw-r--r-- | java/jni/CMakeLists.txt | 38 | ||||
-rw-r--r-- | java/jni/HCIManager.cxx | 30 | ||||
-rw-r--r-- | java/jni/HCIObject.cxx | 34 | ||||
-rw-r--r-- | java/jni/JNIMem.cxx | 31 | ||||
-rw-r--r-- | java/jni/JNIMem.hpp | 28 | ||||
-rw-r--r-- | java/jni/direct_bt/CMakeLists.txt | 53 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTAdapter.cxx | 259 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTDevice.cxx | 78 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTEvent.cxx (renamed from java/jni/HCIEvent.cxx) | 20 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTGattCharacteristic.cxx (renamed from java/jni/HCIGattCharacteristic.cxx) | 6 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTGattDescriptor.cxx (renamed from java/jni/HCIDevice.cxx) | 6 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTGattService.cxx (renamed from java/jni/HCIGattService.cxx) | 6 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTManager.cxx | 106 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTNativeDownlink.cxx | 58 | ||||
-rw-r--r-- | java/jni/direct_bt/DBTObject.cxx (renamed from java/jni/HCIAdapter.cxx) | 6 | ||||
-rw-r--r-- | java/jni/direct_bt/helper_dbt.cxx | 65 | ||||
-rw-r--r-- | java/jni/direct_bt/helper_dbt.hpp | 113 | ||||
-rw-r--r-- | java/jni/helper_base.cxx | 27 | ||||
-rw-r--r-- | java/jni/helper_base.hpp | 68 | ||||
-rw-r--r-- | java/jni/tinyb/CMakeLists.txt | 54 | ||||
-rw-r--r-- | java/jni/tinyb/DBusAdapter.cxx (renamed from java/jni/DBusAdapter.cxx) | 0 | ||||
-rw-r--r-- | java/jni/tinyb/DBusDevice.cxx (renamed from java/jni/DBusDevice.cxx) | 0 | ||||
-rw-r--r-- | java/jni/tinyb/DBusEvent.cxx (renamed from java/jni/DBusEvent.cxx) | 0 | ||||
-rw-r--r-- | java/jni/tinyb/DBusGattCharacteristic.cxx (renamed from java/jni/DBusGattCharacteristic.cxx) | 0 | ||||
-rw-r--r-- | java/jni/tinyb/DBusGattDescriptor.cxx (renamed from java/jni/DBusGattDescriptor.cxx) | 0 | ||||
-rw-r--r-- | java/jni/tinyb/DBusGattService.cxx (renamed from java/jni/DBusGattService.cxx) | 0 | ||||
-rw-r--r-- | java/jni/tinyb/DBusManager.cxx (renamed from java/jni/DBusManager.cxx) | 0 | ||||
-rw-r--r-- | java/jni/tinyb/DBusObject.cxx (renamed from java/jni/DBusObject.cxx) | 0 | ||||
-rw-r--r-- | java/jni/tinyb/helper_tinyb.cxx (renamed from java/jni/helper_tinyb.cxx) | 36 | ||||
-rw-r--r-- | java/jni/tinyb/helper_tinyb.hpp (renamed from java/jni/helper_tinyb.hpp) | 12 | ||||
-rw-r--r-- | java/org/tinyb/BluetoothAdapter.java | 6 | ||||
-rw-r--r-- | java/org/tinyb/BluetoothDeviceDiscoveryListener.java | 42 | ||||
-rw-r--r-- | java/org/tinyb/BluetoothFactory.java | 10 | ||||
-rw-r--r-- | java/org/tinyb/BluetoothManager.java | 9 | ||||
-rw-r--r-- | java/org/tinyb/BluetoothUtils.java (renamed from java/jni/HCIGattDescriptor.cxx) | 16 | ||||
-rw-r--r-- | java/tinyb/dbus/DBusAdapter.java | 6 | ||||
-rw-r--r-- | java/tinyb/dbus/DBusManager.java | 5 | ||||
-rw-r--r-- | java/tinyb/hci/HCIAdapter.java | 199 |
49 files changed, 1754 insertions, 469 deletions
diff --git a/java/CMakeLists.txt b/java/CMakeLists.txt index 1f3b1771..ba7c017b 100644 --- a/java/CMakeLists.txt +++ b/java/CMakeLists.txt @@ -27,4 +27,5 @@ add_custom_command (TARGET tinybjar set(JNI_HEADER_PATH "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/tinybjar.dir/jni") install (FILES ${CMAKE_CURRENT_BINARY_DIR}/tinyb2.jar DESTINATION ${CMAKE_INSTALL_LIBDIR}/../lib/java) -add_subdirectory (jni) +add_subdirectory (jni/direct_bt) +add_subdirectory (jni/tinyb) diff --git a/java/direct_bt/tinyb/Adapter.java b/java/direct_bt/tinyb/Adapter.java new file mode 100644 index 00000000..b953c318 --- /dev/null +++ b/java/direct_bt/tinyb/Adapter.java @@ -0,0 +1,417 @@ +/** + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package direct_bt.tinyb; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; + +import org.tinyb.BluetoothAdapter; +import org.tinyb.BluetoothDevice; +import org.tinyb.BluetoothException; +import org.tinyb.BluetoothManager; +import org.tinyb.BluetoothNotification; +import org.tinyb.BluetoothType; +import org.tinyb.BluetoothDeviceDiscoveryListener; +import org.tinyb.TransportType; + +public class Adapter extends DBTObject implements BluetoothAdapter +{ + private final String address; + private final String name; + private final DiscoveryThread discoveryThread; + + /* pp */ Adapter(final long nativeInstance, final String address, final String name) + { + super(nativeInstance, compHash(address, name)); + this.address = address; + this.name = name; + this.discoveryThread = new DiscoveryThread(); + this.discoveryThread.start(null); + initImpl(this.discoveryThread.deviceDiscoveryListener); + } + + @Override + public synchronized void close() { + discoveryThread.stop(); + super.close(); + } + + @Override + public boolean equals(final Object obj) + { + if (obj == null || !(obj instanceof Device)) { + return false; + } + final Adapter other = (Adapter)obj; + return address.equals(other.address) && name.equals(other.name); + } + + @Override + public String getAddress() { return address; } + + @Override + public String getName() { return name; } + + public String getInterfaceName() { + throw new UnsupportedOperationException(); // FIXME + } + + @Override + public BluetoothType getBluetoothType() { return class_type(); } + + static BluetoothType class_type() { return BluetoothType.ADAPTER; } + + @Override + public final BluetoothAdapter clone() + { throw new UnsupportedOperationException(); } // FIXME + + @Override + public BluetoothDevice find(final String name, final String address, final long timeoutMS) { + final BluetoothManager manager = Manager.getBluetoothManager(); + return (BluetoothDevice) manager.find(BluetoothType.DEVICE, name, address, this, timeoutMS); + } + + @Override + public BluetoothDevice find(final String name, final String address) { + return find(name, address, 0); + } + + @Override + public String toString() { + final StringBuilder out = new StringBuilder(); + out.append("Adapter[").append(getAddress()).append(", '").append(getName()).append("', id=").append("]"); + synchronized(discoveryThread.discoveredDevicesLock) { + final int count = discoveryThread.discoveredDevices.size(); + if( count > 0 ) { + out.append("\n"); + for(final Iterator<BluetoothDevice> iter=discoveryThread.discoveredDevices.iterator(); iter.hasNext(); ) { + final BluetoothDevice device = iter.next(); + out.append(" ").append(device.toString()).append("\n"); + } + } + } + return out.toString(); + } + + /* property accessors: */ + + @Override + public String getAlias() { throw new UnsupportedOperationException(); } // FIXME + + @Override + public void setAlias(final String value) { throw new UnsupportedOperationException(); } // FIXME + + @Override + public long getBluetoothClass() { throw new UnsupportedOperationException(); } // FIXME + + @Override + public native boolean getPowered(); + + @Override + public native void enablePoweredNotifications(BluetoothNotification<Boolean> callback); + + @Override + public native void disablePoweredNotifications(); + + @Override + public native void setPowered(boolean value); + + @Override + public native boolean getDiscoverable(); + + @Override + public native void enableDiscoverableNotifications(BluetoothNotification<Boolean> callback); + + @Override + public native void disableDiscoverableNotifications(); + + @Override + public native void setDiscoverable(boolean value); + + @Override + public native long getDiscoverableTimeout(); + + @Override + public native void setDiscoverableTimout(long value); + + @Override + public native BluetoothDevice connectDevice(String address, String addressType); + + @Override + public native boolean getPairable(); + + @Override + public native void enablePairableNotifications(BluetoothNotification<Boolean> callback); + + @Override + public native void disablePairableNotifications(); + + @Override + public native void setPairable(boolean value); + + @Override + public native long getPairableTimeout(); + + @Override + public native void setPairableTimeout(long value); + + @Override + public native String[] getUUIDs(); + + @Override + public native String getModalias(); + + /* internal */ + + private native void initImpl(final BluetoothDeviceDiscoveryListener l); + + @Override + protected native void deleteImpl(); + + /* discovery */ + + @Override + public boolean startDiscovery() throws BluetoothException { + return discoveryThread.doDiscovery(true); + } + private native boolean startDiscoveryImpl() throws BluetoothException; + + @Override + public boolean stopDiscovery() throws BluetoothException { + return discoveryThread.doDiscovery(false); + } + private native boolean stopDiscoveryImpl() throws BluetoothException; + + @Override + public List<BluetoothDevice> getDevices() { + return discoveryThread.getDiscoveredDevices(); + } + + @Override + public int removeDevices() throws BluetoothException { + final int cj = discoveryThread.removeDiscoveredDevices(); + final int cn = removeDevicesImpl(); + if( cj != cn ) { + throw new InternalError("Inconsistent discovered device count: Native "+cn+", callback "+cj); + } + return cn; + } + private native int removeDevicesImpl() throws BluetoothException; + + @Override + public boolean getDiscovering() { return discoveryThread.running && discoveryThread.doDiscovery; } + + @Override + public void setDeviceDiscoveryListener(final BluetoothDeviceDiscoveryListener l) { + discoveryThread.setDeviceDiscoveryListener(l); + } + + @Override + public void enableDiscoveringNotifications(final BluetoothNotification<Boolean> callback) { + discoveryThread.setDiscoveringNotificationCallback(callback); + } + + @Override + public void disableDiscoveringNotifications() { + discoveryThread.setDiscoveringNotificationCallback(null); + } + + @Override + public void setDiscoveryFilter(final List<UUID> uuids, final int rssi, final int pathloss, final TransportType transportType) { + final List<String> uuidsFmt = new ArrayList<>(uuids.size()); + for (final UUID uuid : uuids) { + uuidsFmt.add(uuid.toString()); + } + setDiscoveryFilter(uuidsFmt, rssi, pathloss, transportType.ordinal()); + } + + public void setRssiDiscoveryFilter(final int rssi) { + setDiscoveryFilter(Collections.EMPTY_LIST, rssi, 0, TransportType.AUTO); + } + + private native void setDiscoveryFilter(List<String> uuids, int rssi, int pathloss, int transportType); + + private native int discoverAnyDeviceImpl(final int timeoutMS) throws BluetoothException; + // std::vector<std::shared_ptr<direct_bt::HCIDevice>> discoveredDevices = adapter.getDiscoveredDevices(); + private native List<BluetoothDevice> getDiscoveredDevicesImpl(); + + private class DiscoveryThread implements Runnable { + private int instanceID=-1; + + private volatile boolean running = false; + private volatile boolean doDiscovery = false; + private final Object stateLock = new Object(); + private volatile BluetoothDeviceDiscoveryListener userDeviceDiscoveryListener = null; + private volatile BluetoothNotification<Boolean> discoveringNotificationCB = null; + private List<BluetoothDevice> discoveredDevices = new ArrayList<BluetoothDevice>(); + private final Object discoveredDevicesLock = new Object(); + + private final BluetoothDeviceDiscoveryListener deviceDiscoveryListener = new BluetoothDeviceDiscoveryListener() { + @Override + public void deviceAdded(final BluetoothAdapter a, final BluetoothDevice device) { + final BluetoothDeviceDiscoveryListener l = userDeviceDiscoveryListener; + System.err.println("DBTAdapter.DeviceDiscoveryListener.added: "+device+" on "+a); + synchronized(discoveredDevicesLock) { + discoveredDevices.add(device); + } + if( null != l ) { + l.deviceAdded(a, device); + } + } + + @Override + public void deviceUpdated(final BluetoothAdapter a, final BluetoothDevice device) { + System.err.println("DBTAdapter.DeviceDiscoveryListener.updated: "+device+" on "+a); + // nop on discoveredDevices + userDeviceDiscoveryListener.deviceUpdated(a, device); + } + + @Override + public void deviceRemoved(final BluetoothAdapter a, final BluetoothDevice device) { + final BluetoothDeviceDiscoveryListener l = userDeviceDiscoveryListener; + System.err.println("DBTAdapter.DeviceDiscoveryListener.removed: "+device+" on "+a); + synchronized(discoveredDevicesLock) { + discoveredDevices.remove(device); + } + if( null != l ) { + l.deviceRemoved(a, device); + } + } + }; + + public void start(final ThreadGroup tg) { + synchronized( stateLock ) { + if ( !running ) { + instanceID = globThreadID.addAndGet(1); + final Thread t = new Thread(tg, this, "Adapter-"+instanceID); // Thread name aligned w/ 'Thread-#' + t.setDaemon(true); + t.start(); + while( !running ) { + try { + stateLock.wait(); + } catch (final InterruptedException e) { + e.printStackTrace(); + } + } + } + } + } + public void setDeviceDiscoveryListener(final BluetoothDeviceDiscoveryListener l) { + synchronized( stateLock ) { + userDeviceDiscoveryListener = l; + stateLock.notifyAll(); + } + } + public void setDiscoveringNotificationCallback(final BluetoothNotification<Boolean> cb) { + synchronized( stateLock ) { + discoveringNotificationCB = cb; + stateLock.notifyAll(); + } + } + public List<BluetoothDevice> getDiscoveredDevices() { + synchronized(discoveredDevicesLock) { + return new ArrayList<BluetoothDevice>(discoveredDevices); + } + } + public int removeDiscoveredDevices() { + synchronized(discoveredDevicesLock) { + final int n = discoveredDevices.size(); + discoveredDevices = new ArrayList<BluetoothDevice>(); + return n; + } + } + public boolean doDiscovery(final boolean v) { + synchronized( stateLock ) { + if( v == doDiscovery ) { + return v; + } + final BluetoothNotification<Boolean> cb = discoveringNotificationCB; + final boolean enable; + if( v ) { + enable = startDiscoveryImpl(); + } else { + enable = false; + stopDiscoveryImpl(); + } + doDiscovery = enable; + if( null != cb ) { + cb.run(enable); + } + stateLock.notifyAll(); + return enable; + } + } + public void stop() { + synchronized( stateLock ) { + stopDiscoveryImpl(); + running = false; + doDiscovery = false; + stateLock.notifyAll(); + } + } + + @Override + public void run() { + synchronized( stateLock ) { + running = true; + stateLock.notifyAll(); + } + while (running) { + synchronized( stateLock ) { + while( running && !doDiscovery ) { + try { + stateLock.wait(); + } catch (final InterruptedException e) { + e.printStackTrace(); + } + } + } + if( !running ) { + break; // end loop and thread + } + + try { + if( doDiscovery ) { + // will trigger all discovery callbacks! + discoverAnyDeviceImpl(discoverTimeoutMS); + } + } catch (final Exception e) { + System.err.println(e.toString()); + e.printStackTrace(); + doDiscovery = false; + } + } // loop + + instanceID = -1; + } + } + private static AtomicInteger globThreadID = new AtomicInteger(0); + private static int discoverTimeoutMS = 100; +} diff --git a/java/tinyb/hci/HCIEvent.java b/java/direct_bt/tinyb/DBTEvent.java index 4dc30ec3..66317ea9 100644 --- a/java/tinyb/hci/HCIEvent.java +++ b/java/direct_bt/tinyb/DBTEvent.java @@ -23,13 +23,13 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package tinyb.hci; +package direct_bt.tinyb; import org.tinyb.BluetoothCallback; import org.tinyb.BluetoothEvent; import org.tinyb.BluetoothType; -public class HCIEvent implements BluetoothEvent +public class DBTEvent implements BluetoothEvent { private long nativeInstance; @@ -45,11 +45,11 @@ public class HCIEvent implements BluetoothEvent public native boolean hasCallback(); private native void init(BluetoothType type, String name, String identifier, - HCIObject parent, BluetoothCallback cb, Object data); + DBTObject parent, BluetoothCallback cb, Object data); private native void delete(); - public HCIEvent(final BluetoothType type, final String name, final String identifier, - final HCIObject parent, final BluetoothCallback cb, final Object data) + public DBTEvent(final BluetoothType type, final String name, final String identifier, + final DBTObject parent, final BluetoothCallback cb, final Object data) { init(type, name, identifier, parent, cb, data); } diff --git a/java/tinyb/hci/HCIObject.java b/java/direct_bt/tinyb/DBTObject.java index 85a903e5..93b10245 100644 --- a/java/tinyb/hci/HCIObject.java +++ b/java/direct_bt/tinyb/DBTObject.java @@ -23,28 +23,14 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package tinyb.hci; +package direct_bt.tinyb; -import org.tinyb.BluetoothFactory; import org.tinyb.BluetoothObject; import org.tinyb.BluetoothType; -public abstract class HCIObject implements BluetoothObject +public abstract class DBTObject extends NativeDownlink implements BluetoothObject { private final int hashValue; - private boolean isValid; - - static { - try { - System.loadLibrary(BluetoothFactory.JavaNativeLibBasename); - } catch (final Throwable e) { - System.err.println("Failed to load native library "+BluetoothFactory.JavaNativeLibBasename); - e.printStackTrace(); - throw e; // fwd exception - end here - } - } - - static BluetoothType class_type() { return BluetoothType.NONE; } /* pp */ static int compHash(final String a, final String b) { // 31 * x == (x << 5) - x @@ -52,12 +38,14 @@ public abstract class HCIObject implements BluetoothObject return ((hash << 5) - hash) + b.hashCode(); } - protected HCIObject(final int hashValue) + protected DBTObject(final long nativeInstance, final int hashValue) { + super(nativeInstance); this.hashValue = hashValue; - isValid = true; } + static BluetoothType class_type() { return BluetoothType.NONE; } + @Override public abstract boolean equals(final Object obj); @@ -74,18 +62,11 @@ public abstract class HCIObject implements BluetoothObject @Override public synchronized void close() { - if (!isValid) { - return; - } - isValid = false; delete(); } - @Override - public native BluetoothType getBluetoothType(); @Override public BluetoothObject clone() { throw new UnsupportedOperationException(); } // FIXME - private native void delete(); } diff --git a/java/tinyb/hci/HCIDevice.java b/java/direct_bt/tinyb/Device.java index b9a41a53..f3a90d6b 100644 --- a/java/tinyb/hci/HCIDevice.java +++ b/java/direct_bt/tinyb/Device.java @@ -23,7 +23,7 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package tinyb.hci; +package direct_bt.tinyb; import java.util.List; import java.util.Map; @@ -34,30 +34,34 @@ import org.tinyb.BluetoothGattService; import org.tinyb.BluetoothManager; import org.tinyb.BluetoothNotification; import org.tinyb.BluetoothType; +import org.tinyb.BluetoothUtils; -import tinyb.dbus.DBusObject; - -public class HCIDevice extends HCIObject implements BluetoothDevice +public class Device extends DBTObject implements BluetoothDevice { - private final HCIAdapter adapter; + private final Adapter adapter; private final String address; private final String name; + private final long ts_creation; + long ts_update; - /* pp */ HCIDevice(final HCIAdapter adptr, final String address, final String name) + /* pp */ Device(final long nativeInstance, final Adapter adptr, final String address, final String name, final long ts_creation) { - super(compHash(address, name)); + super(nativeInstance, compHash(address, name)); this.adapter = adptr; this.address = address; this.name = name; + this.ts_creation = ts_creation; + ts_update = ts_creation; + initImpl(); } @Override public boolean equals(final Object obj) { - if (obj == null || !(obj instanceof HCIDevice)) { + if (obj == null || !(obj instanceof Device)) { return false; } - final HCIDevice other = (HCIDevice)obj; + final Device other = (Device)obj; return address.equals(other.address) && name.equals(other.name); } @@ -70,14 +74,15 @@ public class HCIDevice extends HCIObject implements BluetoothDevice @Override public BluetoothType getBluetoothType() { return class_type(); } - @Override - public native HCIDevice clone(); - static BluetoothType class_type() { return BluetoothType.DEVICE; } @Override + public final BluetoothDevice clone() + { throw new UnsupportedOperationException(); } // FIXME + + @Override public BluetoothGattService find(final String UUID, final long timeoutMS) { - final BluetoothManager manager = HCIManager.getBluetoothManager(); + final BluetoothManager manager = Manager.getBluetoothManager(); return (BluetoothGattService) manager.find(BluetoothType.GATT_SERVICE, null, UUID, this, timeoutMS); } @@ -87,6 +92,34 @@ public class HCIDevice extends HCIObject implements BluetoothDevice return find(UUID, 0); } + @Override + public String toString() { + final StringBuilder out = new StringBuilder(); + final long t0 = BluetoothUtils.getCurrentMilliseconds(); + // std::string msdstr = nullptr != msd ? msd->toString() : "MSD[null]"; + final String msdstr = "MSD[null]"; + out.append("Device[").append(getAddress()).append(", '").append(getName()) + .append("', age ").append(t0-ts_creation).append(" ms, lup ").append(t0-ts_update).append(" ms, rssi ").append(getRSSI()) + .append(", tx-power ").append(getTxPower()).append(", ").append(msdstr).append("]"); + /** + if(services.size() > 0 ) { + out.append("\n"); + final int i=0; + for(final auto it = services.begin(); it != services.end(); it++, i++) { + if( 0 < i ) { + out.append("\n"); + } + std::shared_ptr<uuid_t> p = *it; + out.append(" ").append(p->toUUID128String()).append(", ").append(std::to_string(static_cast<int>(p->getTypeSize()))).append(" bytes"); + } + } */ + return out.toString(); + } + + /* internal */ + + private native void initImpl(); + /* D-Bus method calls: */ @Override @@ -194,7 +227,7 @@ public class HCIDevice extends HCIObject implements BluetoothDevice public native String getModalias(); @Override - public native HCIAdapter getAdapter(); + public native Adapter getAdapter(); @Override public native Map<Short, byte[]> getManufacturerData(); @@ -227,5 +260,6 @@ public class HCIDevice extends HCIObject implements BluetoothDevice @Override public native void disableServicesResolvedNotifications(); - private native void delete(); + @Override + protected native void deleteImpl(); } diff --git a/java/tinyb/hci/HCIGattCharacteristic.java b/java/direct_bt/tinyb/GattCharacteristic.java index a2047e1e..801dac33 100644 --- a/java/tinyb/hci/HCIGattCharacteristic.java +++ b/java/direct_bt/tinyb/GattCharacteristic.java @@ -23,10 +23,11 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package tinyb.hci; +package direct_bt.tinyb; import java.util.List; +import org.tinyb.BluetoothDevice; import org.tinyb.BluetoothException; import org.tinyb.BluetoothGattCharacteristic; import org.tinyb.BluetoothGattDescriptor; @@ -35,23 +36,23 @@ import org.tinyb.BluetoothManager; import org.tinyb.BluetoothNotification; import org.tinyb.BluetoothType; -public class HCIGattCharacteristic extends HCIObject implements BluetoothGattCharacteristic +public class GattCharacteristic extends DBTObject implements BluetoothGattCharacteristic { private final String uuid; - /* pp */ HCIGattCharacteristic(final String uuid) + /* pp */ GattCharacteristic(final long nativeInstance, final String uuid) { - super(uuid.hashCode()); + super(nativeInstance, uuid.hashCode()); this.uuid = uuid; } @Override public boolean equals(final Object obj) { - if (obj == null || !(obj instanceof HCIGattCharacteristic)) { + if (obj == null || !(obj instanceof GattCharacteristic)) { return false; } - final HCIGattCharacteristic other = (HCIGattCharacteristic)obj; + final GattCharacteristic other = (GattCharacteristic)obj; return uuid.equals(other.uuid); } @@ -59,15 +60,17 @@ public class HCIGattCharacteristic extends HCIObject implements BluetoothGattCha public String getUUID() { return uuid; } @Override - public native BluetoothType getBluetoothType(); - @Override - public native HCIGattCharacteristic clone(); + public BluetoothType getBluetoothType() { return class_type(); } static BluetoothType class_type() { return BluetoothType.GATT_CHARACTERISTIC; } @Override + public final GattCharacteristic clone() + { throw new UnsupportedOperationException(); } // FIXME + + @Override public BluetoothGattDescriptor find(final String UUID, final long timeoutMS) { - final BluetoothManager manager = HCIManager.getBluetoothManager(); + final BluetoothManager manager = Manager.getBluetoothManager(); return (BluetoothGattDescriptor) manager.find(BluetoothType.GATT_DESCRIPTOR, null, UUID, this, timeoutMS); } @@ -108,8 +111,9 @@ public class HCIGattCharacteristic extends HCIObject implements BluetoothGattCha @Override public native List<BluetoothGattDescriptor> getDescriptors(); - private native void init(HCIGattCharacteristic obj); + private native void init(GattCharacteristic obj); - private native void delete(); + @Override + protected native void deleteImpl(); } diff --git a/java/tinyb/hci/HCIGattDescriptor.java b/java/direct_bt/tinyb/GattDescriptor.java index b04816a4..5b0d2898 100644 --- a/java/tinyb/hci/HCIGattDescriptor.java +++ b/java/direct_bt/tinyb/GattDescriptor.java @@ -23,30 +23,30 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package tinyb.hci; +package direct_bt.tinyb; import org.tinyb.BluetoothException; import org.tinyb.BluetoothGattDescriptor; import org.tinyb.BluetoothNotification; import org.tinyb.BluetoothType; -public class HCIGattDescriptor extends HCIObject implements BluetoothGattDescriptor +public class GattDescriptor extends DBTObject implements BluetoothGattDescriptor { private final String uuid; - /* pp */ HCIGattDescriptor(final String uuid) + /* pp */ GattDescriptor(final long nativeInstance, final String uuid) { - super(uuid.hashCode()); + super(nativeInstance, uuid.hashCode()); this.uuid = uuid; } @Override public boolean equals(final Object obj) { - if (obj == null || !(obj instanceof HCIGattDescriptor)) { + if (obj == null || !(obj instanceof GattDescriptor)) { return false; } - final HCIGattDescriptor other = (HCIGattDescriptor)obj; + final GattDescriptor other = (GattDescriptor)obj; return uuid.equals(other.uuid); } @@ -54,12 +54,14 @@ public class HCIGattDescriptor extends HCIObject implements BluetoothGattDescrip public String getUUID() { return uuid; } @Override - public native BluetoothType getBluetoothType(); - @Override - public native BluetoothGattDescriptor clone(); + public BluetoothType getBluetoothType() { return class_type(); } static BluetoothType class_type() { return BluetoothType.GATT_DESCRIPTOR; } + @Override + public final GattDescriptor clone() + { throw new UnsupportedOperationException(); } // FIXME + /* D-Bus method calls: */ @Override @@ -77,10 +79,11 @@ public class HCIGattDescriptor extends HCIObject implements BluetoothGattDescrip /* D-Bus property accessors: */ @Override - public native HCIGattCharacteristic getCharacteristic(); + public native GattCharacteristic getCharacteristic(); @Override public native byte[] getValue(); - private native void delete(); + @Override + protected native void deleteImpl(); } diff --git a/java/tinyb/hci/HCIGattService.java b/java/direct_bt/tinyb/GattService.java index 584f68b3..8377c806 100644 --- a/java/tinyb/hci/HCIGattService.java +++ b/java/direct_bt/tinyb/GattService.java @@ -23,7 +23,7 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package tinyb.hci; +package direct_bt.tinyb; import java.util.List; @@ -32,23 +32,23 @@ import org.tinyb.BluetoothGattService; import org.tinyb.BluetoothManager; import org.tinyb.BluetoothType; -public class HCIGattService extends HCIObject implements BluetoothGattService +public class GattService extends DBTObject implements BluetoothGattService { private final String uuid; - /* pp */ HCIGattService(final String uuid) + /* pp */ GattService(final long nativeInstance, final String uuid) { - super(uuid.hashCode()); + super(nativeInstance, uuid.hashCode()); this.uuid = uuid; } @Override public boolean equals(final Object obj) { - if (obj == null || !(obj instanceof HCIGattService)) { + if (obj == null || !(obj instanceof GattService)) { return false; } - final HCIGattService other = (HCIGattService)obj; + final GattService other = (GattService)obj; return uuid.equals(other.uuid); } @@ -56,17 +56,18 @@ public class HCIGattService extends HCIObject implements BluetoothGattService public String getUUID() { return uuid; } @Override - public native BluetoothType getBluetoothType(); - - @Override - public native BluetoothGattService clone(); + public BluetoothType getBluetoothType() { return class_type(); } static BluetoothType class_type() { return BluetoothType.GATT_SERVICE; } @Override + public final GattService clone() + { throw new UnsupportedOperationException(); } // FIXME + + @Override public BluetoothGattCharacteristic find(final String UUID, final long timeoutMS) { - final BluetoothManager manager = HCIManager.getBluetoothManager(); - return (HCIGattCharacteristic) manager.find(BluetoothType.GATT_CHARACTERISTIC, + final BluetoothManager manager = Manager.getBluetoothManager(); + return (GattCharacteristic) manager.find(BluetoothType.GATT_CHARACTERISTIC, null, UUID, this, timeoutMS); } @@ -78,7 +79,7 @@ public class HCIGattService extends HCIObject implements BluetoothGattService /* D-Bus property accessors: */ @Override - public native HCIDevice getDevice(); + public native Device getDevice(); @Override public native boolean getPrimary(); @@ -86,5 +87,6 @@ public class HCIGattService extends HCIObject implements BluetoothGattService @Override public native List<BluetoothGattCharacteristic> getCharacteristics(); - private native void delete(); + @Override + protected native void deleteImpl(); } diff --git a/java/tinyb/hci/HCIManager.java b/java/direct_bt/tinyb/Manager.java index 7afba39c..99ea2cce 100644 --- a/java/tinyb/hci/HCIManager.java +++ b/java/direct_bt/tinyb/Manager.java @@ -23,7 +23,7 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package tinyb.hci; +package direct_bt.tinyb; import java.util.ArrayList; import java.util.List; @@ -36,30 +36,31 @@ import org.tinyb.BluetoothObject; import org.tinyb.BluetoothManager; import org.tinyb.BluetoothType; -public class HCIManager implements BluetoothManager +public class Manager implements BluetoothManager { - private static HCIManager inst; + private long nativeInstance; + private static Manager inst; private final List<BluetoothAdapter> adapters = new ArrayList<BluetoothAdapter>(); - public native BluetoothType getBluetoothType(); + public BluetoothType getBluetoothType() { return BluetoothType.NONE; } - private HCIObject find(final int type, final String name, final String identifier, final BluetoothObject parent, final long milliseconds) + private DBTObject find(final int type, final String name, final String identifier, final BluetoothObject parent, final long milliseconds) { throw new UnsupportedOperationException(); } // FIXME @Override - public HCIObject find(final BluetoothType type, final String name, final String identifier, final BluetoothObject parent, final long timeoutMS) { + public DBTObject find(final BluetoothType type, final String name, final String identifier, final BluetoothObject parent, final long timeoutMS) { return find(type.ordinal(), name, identifier, parent, timeoutMS); } @Override - public HCIObject find(final BluetoothType type, final String name, final String identifier, final BluetoothObject parent) { + public DBTObject find(final BluetoothType type, final String name, final String identifier, final BluetoothObject parent) { return find(type, name, identifier, parent, 0); } @SuppressWarnings("unchecked") @Override public <T extends BluetoothObject> T find(final String name, final String identifier, final BluetoothObject parent, final long timeoutMS) { - return (T) find(HCIObject.class_type().ordinal(), name, identifier, parent, timeoutMS); + return (T) find(DBTObject.class_type().ordinal(), name, identifier, parent, timeoutMS); } @SuppressWarnings("unchecked") @@ -108,12 +109,22 @@ public class HCIManager implements BluetoothManager @Override public boolean getDiscovering() throws BluetoothException { return getDefaultAdapter().getDiscovering(); } - private native HCIAdapter init() throws BluetoothException; - private native void delete(); + /** + * Returns an opened default adapter instance! + * @throws BluetoothException in case adapter is invalid or could not have been opened. + */ + private native Adapter getDefaultAdapterImpl() throws BluetoothException; - private HCIManager() + private native void initImpl() throws BluetoothException; + private native void deleteImpl(); + private Manager() { - adapters.add(init()); + initImpl(); + try { + adapters.add(getDefaultAdapterImpl()); + } catch (final BluetoothException be) { + be.printStackTrace(); + } } /** Returns an instance of BluetoothManager, to be used instead of constructor. @@ -123,15 +134,20 @@ public class HCIManager implements BluetoothManager { if (inst == null) { - inst = new HCIManager(); + inst = new Manager(); } return inst; } @Override - protected void finalize() - { + protected void finalize() { + shutdown(); + } + + @Override + public void shutdown() { adapters.clear(); - delete(); + deleteImpl(); } + } diff --git a/java/direct_bt/tinyb/NativeDownlink.java b/java/direct_bt/tinyb/NativeDownlink.java new file mode 100644 index 00000000..72e4e137 --- /dev/null +++ b/java/direct_bt/tinyb/NativeDownlink.java @@ -0,0 +1,87 @@ +/** + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package direct_bt.tinyb; + +import org.tinyb.BluetoothFactory; + +public abstract class NativeDownlink +{ + protected long nativeInstance; + private boolean isValid; + + static { + try { + System.loadLibrary(BluetoothFactory.JavaNativeLibBasename); + } catch (final Throwable e) { + System.err.println("Failed to load native library "+BluetoothFactory.JavaNativeLibBasename); + e.printStackTrace(); + throw e; // fwd exception - end here + } + } + + protected NativeDownlink(final long nativeInstance) + { + this.nativeInstance = nativeInstance; + isValid = true; + initNativeJavaObject(nativeInstance); + } + + @Override + protected void finalize() + { + delete(); + } + + /** + * Deletes the native instance in the following order + * <ol> + * <li>Removes this java reference from the native instance</li> + * <li>Deletes the native instance via {@link #deleteImpl()}</li> + * <li>Sets the nativeInstance := 0</li> + * </ol> + */ + public synchronized void delete() { + if (!isValid) { + return; + } + isValid = false; + clearNativeJavaObject(nativeInstance); + deleteImpl(); + nativeInstance = 0; + } + + /** + * Deletes the native instance. + * <p> + * Called via {@link #delete()} and at this point this java reference + * has been removed from the native instance. + * </p> + */ + protected abstract void deleteImpl(); + + private native void initNativeJavaObject(final long nativeInstance); + private native void clearNativeJavaObject(final long nativeInstance); +} diff --git a/java/jni/BluetoothUtils.cxx b/java/jni/BluetoothUtils.cxx new file mode 100644 index 00000000..83e71dd0 --- /dev/null +++ b/java/jni/BluetoothUtils.cxx @@ -0,0 +1,53 @@ +/* + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "org_tinyb_BluetoothUtils.h" + +#include <cstdint> +#include <cinttypes> + +#include <time.h> + +static const int64_t NanoPerMilli = 1000000L; +static const int64_t MilliPerOne = 1000L; + +/** + * See <http://man7.org/linux/man-pages/man2/clock_gettime.2.html> + * <p> + * Regarding avoiding kernel via VDSO, + * see <http://man7.org/linux/man-pages/man7/vdso.7.html>, + * clock_gettime seems to be well supported at least on kernel >= 4.4. + * Only bfin and sh are missing, while ia64 seems to be complicated. + */ +jlong Java_org_tinyb_BluetoothUtils_getCurrentMilliseconds(JNIEnv *env, jclass clazz) { + (void)env; + (void)clazz; + + struct timespec t; + clock_gettime(CLOCK_MONOTONIC, &t); + int64_t res = t.tv_sec * MilliPerOne + t.tv_nsec / NanoPerMilli; + return (jlong)res; +} + diff --git a/java/jni/CMakeLists.txt b/java/jni/CMakeLists.txt deleted file mode 100644 index cd715a5a..00000000 --- a/java/jni/CMakeLists.txt +++ /dev/null @@ -1,38 +0,0 @@ -find_package(JNI REQUIRED) - -if (JNI_FOUND) - message (STATUS "JNI_INCLUDE_DIRS=${JNI_INCLUDE_DIRS}") - message (STATUS "JNI_LIBRARIES=${JNI_LIBRARIES}") -endif (JNI_FOUND) - -set (tinyb_LIB_INCLUDE_DIRS - ${PROJECT_SOURCE_DIR}/api - ${PROJECT_SOURCE_DIR}/api/tinyb - ${PROJECT_SOURCE_DIR}/api/direct_bt - ${PROJECT_SOURCE_DIR}/include -) - -include_directories( - ${JNI_INCLUDE_DIRS} - ${tinyb_LIB_INCLUDE_DIRS} - ${JNI_HEADER_PATH} -) - -file(GLOB JNI_SOURCES "*.cxx") - -set (CMAKE_SHARED_LINKER_FLAGS "-Wl,--as-needed") - -add_library (javatinyb SHARED ${JNI_SOURCES}) -target_link_libraries(javatinyb ${JNI_LIBRARIES} tinyb) - -set_target_properties( - javatinyb - PROPERTIES - SOVERSION ${tinyb_VERSION_MAJOR} - VERSION ${tinyb_VERSION_STRING} - CXX_STANDARD 11 - COMPILE_FLAGS "-Wall -Wextra" -) - -install(TARGETS javatinyb LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) - diff --git a/java/jni/HCIManager.cxx b/java/jni/HCIManager.cxx deleted file mode 100644 index 57865644..00000000 --- a/java/jni/HCIManager.cxx +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Author: Sven Gothel <[email protected]> - * Copyright (c) 2020 Gothel Software e.K. - * Copyright (c) 2020 ZAFENA AB - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "direct_bt/HCITypes.hpp" - -#include "JNIMem.hpp" -#include "helper_base.hpp" - diff --git a/java/jni/HCIObject.cxx b/java/jni/HCIObject.cxx deleted file mode 100644 index 1f420eea..00000000 --- a/java/jni/HCIObject.cxx +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Author: Sven Gothel <[email protected]> - * Copyright (c) 2020 Gothel Software e.K. - * Copyright (c) 2020 ZAFENA AB - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "direct_bt/HCITypes.hpp" - -#include "tinyb_hci_HCIObject.h" - -#include "JNIMem.hpp" -#include "helper_base.hpp" - -using namespace direct_bt; - diff --git a/java/jni/JNIMem.cxx b/java/jni/JNIMem.cxx index 9861995c..ecea39aa 100644 --- a/java/jni/JNIMem.cxx +++ b/java/jni/JNIMem.cxx @@ -2,6 +2,10 @@ * Author: Petre Eftime <[email protected]> * Copyright (c) 2016 Intel Corporation. * + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including @@ -60,14 +64,14 @@ void JNIEnvContainer::attach() { if( JNI_EDETACHED == envRes ) { envRes = vm->AttachCurrentThreadAsDaemon((void**) &newEnv, NULL); if( JNI_OK != envRes ) { - throw std::runtime_error("Attach to VM failed"); + throw direct_bt::RuntimeException("Attach to VM failed", E_FILE_LINE); } env = newEnv; } else if( JNI_OK != envRes ) { - throw std::runtime_error("GetEnv of VM failed"); + throw direct_bt::RuntimeException("GetEnv of VM failed", E_FILE_LINE); } if (env==NULL) { - throw std::runtime_error("GetEnv of VM is NULL"); + throw direct_bt::RuntimeException("GetEnv of VM is NULL", E_FILE_LINE); } needsDetach = NULL != newEnv; } @@ -84,13 +88,24 @@ void JNIEnvContainer::detach() { } JNIGlobalRef::JNIGlobalRef(jobject object) { + if( nullptr == object ) { + throw direct_bt::RuntimeException("JNIGlobalRef ctor null jobject", E_FILE_LINE); + } this->object = jni_env->NewGlobalRef(object); } JNIGlobalRef::~JNIGlobalRef() { - jni_env->DeleteGlobalRef(object); -} - -jobject JNIGlobalRef::operator*() { - return object; + try { + JNIEnv * env = *jni_env; + if( nullptr == env ) { + throw direct_bt::RuntimeException("JNIGlobalRef dtor null JNIEnv", E_FILE_LINE); + } + if( nullptr == object ) { + throw direct_bt::RuntimeException("JNIGlobalRef dtor null jobject", E_FILE_LINE); + } else { + env->DeleteGlobalRef(object); + } + } catch (std::exception &e) { + fprintf(stderr, "JNIGlobalRef dtor: Caught %s\n", e.what()); + } } diff --git a/java/jni/JNIMem.hpp b/java/jni/JNIMem.hpp index 389a9157..a133bd9a 100644 --- a/java/jni/JNIMem.hpp +++ b/java/jni/JNIMem.hpp @@ -2,6 +2,10 @@ * Author: Petre Eftime <[email protected]> * Copyright (c) 2016 Intel Corporation. * + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including @@ -22,10 +26,14 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#pragma once +#ifndef JNIMEM__HPP_ +#define JNIMEM__HPP_ + #include <jni.h> #include <stdexcept> +#include "BasicTypes.hpp" + extern JavaVM* vm; @@ -67,12 +75,26 @@ private: jobject object; public: + static inline void check(jobject object, const char* file, int line) { + if( nullptr == object ) { + throw direct_bt::RuntimeException("JNIGlobalRef::check: Null jobject", file, line); + } + } + /* Creates a GlobalRef from an object passed to it */ JNIGlobalRef(jobject object); + /* Deletes the stored GlobalRef */ ~JNIGlobalRef(); - /* Provides access to the stored GlobalRef */ - jobject operator*(); + /* Provides access to the stored GlobalRef as an jobject. */ + jobject operator*() { return object; } + + /* Provides access to the stored GlobalRef as an jobject. */ + jobject getObject() const { return object; } + /* Provides access to the stored GlobalRef as a jclass. */ + jclass getClass() const { return (jclass)object; } }; +#endif /* JNIMEM__HPP_ */ + diff --git a/java/jni/direct_bt/CMakeLists.txt b/java/jni/direct_bt/CMakeLists.txt new file mode 100644 index 00000000..7622569f --- /dev/null +++ b/java/jni/direct_bt/CMakeLists.txt @@ -0,0 +1,53 @@ +find_package(JNI REQUIRED) + +if (JNI_FOUND) + message (STATUS "JNI_INCLUDE_DIRS=${JNI_INCLUDE_DIRS}") + message (STATUS "JNI_LIBRARIES=${JNI_LIBRARIES}") +endif (JNI_FOUND) + +set (direct_bt_LIB_INCLUDE_DIRS + ${PROJECT_SOURCE_DIR}/api + ${PROJECT_SOURCE_DIR}/api/direct_bt + ${PROJECT_SOURCE_DIR}/include + ${PROJECT_SOURCE_DIR}/java/jni +) + +include_directories( + ${JNI_INCLUDE_DIRS} + ${direct_bt_LIB_INCLUDE_DIRS} + ${JNI_HEADER_PATH} +) + +set (direct_bt_JNI_SRCS + ${PROJECT_SOURCE_DIR}/java/jni/JNIMem.cxx + ${PROJECT_SOURCE_DIR}/java/jni/helper_base.cxx + ${PROJECT_SOURCE_DIR}/java/jni/BluetoothFactory.cxx + ${PROJECT_SOURCE_DIR}/java/jni/BluetoothUtils.cxx + ${PROJECT_SOURCE_DIR}/java/jni/direct_bt/helper_dbt.cxx + ${PROJECT_SOURCE_DIR}/java/jni/direct_bt/DBTNativeDownlink.cxx + ${PROJECT_SOURCE_DIR}/java/jni/direct_bt/DBTAdapter.cxx + ${PROJECT_SOURCE_DIR}/java/jni/direct_bt/DBTDevice.cxx + ${PROJECT_SOURCE_DIR}/java/jni/direct_bt/DBTEvent.cxx + ${PROJECT_SOURCE_DIR}/java/jni/direct_bt/DBTGattCharacteristic.cxx + ${PROJECT_SOURCE_DIR}/java/jni/direct_bt/DBTGattDescriptor.cxx + ${PROJECT_SOURCE_DIR}/java/jni/direct_bt/DBTGattService.cxx + ${PROJECT_SOURCE_DIR}/java/jni/direct_bt/DBTManager.cxx + ${PROJECT_SOURCE_DIR}/java/jni/direct_bt/DBTObject.cxx +) + +set (CMAKE_SHARED_LINKER_FLAGS "-Wl,--as-needed") + +add_library (javadirect_bt SHARED ${direct_bt_JNI_SRCS}) +target_link_libraries(javadirect_bt ${JNI_LIBRARIES} direct_bt) + +set_target_properties( + javadirect_bt + PROPERTIES + SOVERSION ${tinyb_VERSION_MAJOR} + VERSION ${tinyb_VERSION_STRING} + CXX_STANDARD 11 + COMPILE_FLAGS "-Wall -Wextra" +) + +install(TARGETS javadirect_bt LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) + diff --git a/java/jni/direct_bt/DBTAdapter.cxx b/java/jni/direct_bt/DBTAdapter.cxx new file mode 100644 index 00000000..3f634dc2 --- /dev/null +++ b/java/jni/direct_bt/DBTAdapter.cxx @@ -0,0 +1,259 @@ +/* + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "direct_bt_tinyb_Adapter.h" + +// #define VERBOSE_ON 1 +#include <dbt_debug.hpp> + +#include "JNIMem.hpp" +#include "helper_base.hpp" +#include "helper_dbt.hpp" + +#include "direct_bt/HCITypes.hpp" + +using namespace direct_bt; + +static const std::string _deviceClazzCtorArgs("(JLdirect_bt/tinyb/Adapter;Ljava/lang/String;Ljava/lang/String;J)V"); +static const std::string _deviceDiscoveryMethodArgs("(Lorg/tinyb/BluetoothAdapter;Lorg/tinyb/BluetoothDevice;)V"); + +class DeviceDiscoveryCallbackListener : public HCIDeviceDiscoveryListener { + public: + /** + package org.tinyb; + + public interface BluetoothDeviceDiscoveryListener { + public void deviceAdded(final BluetoothAdapter adapter, final BluetoothDevice device); + public void deviceUpdated(final BluetoothAdapter adapter, final BluetoothDevice device); + public void deviceRemoved(final BluetoothAdapter adapter, final BluetoothDevice device); + }; + */ + std::shared_ptr<JavaAnonObj> adapterObjRef; + std::unique_ptr<JNIGlobalRef> deviceClazzRef; + jmethodID deviceClazzCtor; + jfieldID deviceClazzTSUpdateField; + std::unique_ptr<JNIGlobalRef> listenerObjRef; + std::unique_ptr<JNIGlobalRef> listenerClazzRef; + jmethodID mDeviceAdded = nullptr; + jmethodID mDeviceUpdated = nullptr; + jmethodID mDeviceRemoved = nullptr; + + DeviceDiscoveryCallbackListener(JNIEnv *env, HCIAdapter *adapter, jobject deviceDiscoveryListener) { + adapterObjRef = adapter->getJavaObject(); + JavaGlobalObj::check(adapterObjRef, E_FILE_LINE); + { + jclass deviceClazz = search_class(*jni_env, HCIDevice::java_class().c_str()); + if( nullptr == deviceClazz ) { + throw InternalError("HCIDevice::java_class not found: "+HCIDevice::java_class(), E_FILE_LINE); + } + deviceClazzRef = std::unique_ptr<JNIGlobalRef>(new JNIGlobalRef(deviceClazz)); + env->DeleteLocalRef(deviceClazz); + } + deviceClazzCtor = search_method(*jni_env, deviceClazzRef->getClass(), "<init>", _deviceClazzCtorArgs.c_str(), false); + if( nullptr == deviceClazzCtor ) { + throw InternalError("HCIDevice::java_class ctor not found: "+HCIDevice::java_class()+".<init>"+_deviceClazzCtorArgs, E_FILE_LINE); + } + deviceClazzTSUpdateField = jni_env->GetFieldID(deviceClazzRef->getClass(), "ts_update", "J"); + if( nullptr == deviceClazzTSUpdateField ) { + throw InternalError("HCIDevice::java_class field not found: "+HCIDevice::java_class()+".ts_update", E_FILE_LINE); + } + + listenerObjRef = std::unique_ptr<JNIGlobalRef>(new JNIGlobalRef(deviceDiscoveryListener)); + { + jclass listenerClazz = search_class(env, listenerObjRef->getObject()); + if( nullptr == listenerClazz ) { + throw InternalError("BluetoothDeviceDiscoveryListener not found", E_FILE_LINE); + } + listenerClazzRef = std::unique_ptr<JNIGlobalRef>(new JNIGlobalRef(listenerClazz)); + env->DeleteLocalRef(listenerClazz); + } + mDeviceAdded = search_method(env, listenerClazzRef->getClass(), "deviceAdded", _deviceDiscoveryMethodArgs.c_str(), false); + mDeviceUpdated = search_method(env, listenerClazzRef->getClass(), "deviceUpdated", _deviceDiscoveryMethodArgs.c_str(), false); + mDeviceRemoved = search_method(env, listenerClazzRef->getClass(), "deviceRemoved", _deviceDiscoveryMethodArgs.c_str(), false); + if( nullptr == mDeviceAdded ) { + throw InternalError("BluetoothDeviceDiscoveryListener has no deviceAdded"+_deviceDiscoveryMethodArgs+" method, for "+adapter->toString(), E_FILE_LINE); + } + if( nullptr == mDeviceUpdated ) { + throw InternalError("BluetoothDeviceDiscoveryListener has no deviceUpdated"+_deviceDiscoveryMethodArgs+" method, for "+adapter->toString(), E_FILE_LINE); + } + if( nullptr == mDeviceRemoved ) { + throw InternalError("BluetoothDeviceDiscoveryListener has no deviceRemoved"+_deviceDiscoveryMethodArgs+" method, for "+adapter->toString(), E_FILE_LINE); + } + exception_check_raise_and_throw(env, E_FILE_LINE); + } + + void deviceAdded(HCIAdapter const &a, std::shared_ptr<HCIDevice> device) override { + try { + #ifdef VERBOSE_ON + fprintf(stderr, "****** Native Adapter Device ADDED__: %s\n", device->toString().c_str()); + fprintf(stderr, "Status HCIAdapter:\n"); + fprintf(stderr, "%s\n", a.toString().c_str()); + #endif + + // Device(final long nativeInstance, final Adapter adptr, final String address, final String name) + const jstring addr = from_string_to_jstring(*jni_env, device->getAddressString()); + const jstring name = from_string_to_jstring(*jni_env, device->getName()); + jobject jDevice = jni_env->NewObject(deviceClazzRef->getClass(), deviceClazzCtor, + (jlong)device.get(), adapterObjRef, addr, name, (jlong)device->ts_creation); + exception_check_raise_and_throw(*jni_env, E_FILE_LINE); + JNIGlobalRef::check(jDevice, E_FILE_LINE); + std::shared_ptr<JavaAnonObj> jDeviceRef = device->getJavaObject(); + JavaGlobalObj::check(jDeviceRef, E_FILE_LINE); + + jni_env->CallVoidMethod(listenerObjRef->getObject(), mDeviceAdded, JavaGlobalObj::GetObject(adapterObjRef), JavaGlobalObj::GetObject(jDeviceRef)); + exception_check_raise_and_throw(*jni_env, E_FILE_LINE); + } CATCH_EXCEPTION_AND_RAISE_JAVA(*jni_env, e) + } + void deviceUpdated(HCIAdapter const &a, std::shared_ptr<HCIDevice> device) override { + try { + #ifdef VERBOSE_ON + fprintf(stderr, "****** Native Adapter Device UPDATED: %s\n", device->toString().c_str()); + fprintf(stderr, "Status HCIAdapter:\n"); + fprintf(stderr, "%s\n", a.toString().c_str()); + #endif + std::shared_ptr<JavaAnonObj> jDeviceRef = device->getJavaObject(); + JavaGlobalObj::check(jDeviceRef, E_FILE_LINE); + jni_env->SetLongField(JavaGlobalObj::GetObject(jDeviceRef), deviceClazzTSUpdateField, (jlong)device->getUpdateTimestamp()); + jni_env->CallVoidMethod(listenerObjRef->getObject(), mDeviceUpdated, JavaGlobalObj::GetObject(adapterObjRef), JavaGlobalObj::GetObject(jDeviceRef)); + exception_check_raise_and_throw(*jni_env, E_FILE_LINE); + } CATCH_EXCEPTION_AND_RAISE_JAVA(*jni_env, e) + } + void deviceRemoved(HCIAdapter const &a, std::shared_ptr<HCIDevice> device) override { + try { + #ifdef VERBOSE_ON + fprintf(stderr, "****** DBTAdapter Device REMOVED: %s\n", device->toString().c_str()); + fprintf(stderr, "Status HCIAdapter:\n"); + fprintf(stderr, "%s\n", a.toString().c_str()); + #endif + std::shared_ptr<JavaAnonObj> jDeviceRef = device->getJavaObject(); + JavaGlobalObj::check(jDeviceRef, E_FILE_LINE); + jni_env->SetLongField(JavaGlobalObj::GetObject(jDeviceRef), deviceClazzTSUpdateField, (jlong)device->getUpdateTimestamp()); + jni_env->CallVoidMethod(listenerObjRef->getObject(), mDeviceRemoved, JavaGlobalObj::GetObject(adapterObjRef), JavaGlobalObj::GetObject(jDeviceRef)); + exception_check_raise_and_throw(*jni_env, E_FILE_LINE); + } CATCH_EXCEPTION_AND_RAISE_JAVA(*jni_env, e) + } +}; + +void Java_direct_1bt_tinyb_Adapter_initImpl(JNIEnv *env, jobject obj, jobject deviceDiscoveryListener) +{ + // org.tinyb.BluetoothDeviceDiscoveryListener + try { + HCIAdapter *adapter = getInstance<HCIAdapter>(env, obj); + JavaGlobalObj::check(adapter->getJavaObject(), E_FILE_LINE); + + // set our callback discovery listener. + DeviceDiscoveryCallbackListener *l = new DeviceDiscoveryCallbackListener(env, adapter, deviceDiscoveryListener); + adapter->setDeviceDiscoveryListener(std::shared_ptr<HCIDeviceDiscoveryListener>(l)); + } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e) +} + +void Java_direct_1bt_tinyb_Adapter_deleteImpl(JNIEnv *env, jobject obj) +{ + try { + HCIAdapter *adapter = getInstance<HCIAdapter>(env, obj); + DBG_PRINT("Java_direct_1bt_tinyb_Adapter_deleteImpl %s", adapter->toString().c_str()); + delete adapter; + } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e) +} + +jboolean Java_direct_1bt_tinyb_Adapter_startDiscoveryImpl(JNIEnv *env, jobject obj) +{ + try { + HCIAdapter *adapter = getInstance<HCIAdapter>(env, obj); + std::shared_ptr<direct_bt::HCISession> session = adapter->getOpenSession(); + if( nullptr == session ) { + throw BluetoothException("No adapter session: "+adapter->toString(), E_FILE_LINE); + } + if( !session->isOpen() ) { + throw BluetoothException("No open adapter session: "+adapter->toString(), E_FILE_LINE); + } + return adapter->startDiscovery(*session); + } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e) + return JNI_FALSE; +} + +jboolean Java_direct_1bt_tinyb_Adapter_stopDiscoveryImpl(JNIEnv *env, jobject obj) +{ + try { + HCIAdapter *adapter = getInstance<HCIAdapter>(env, obj); + std::shared_ptr<direct_bt::HCISession> session = adapter->getOpenSession(); + if( nullptr == session ) { + throw BluetoothException("No adapter session: "+adapter->toString(), E_FILE_LINE); + } + if( !session->isOpen() ) { + throw BluetoothException("No open adapter session: "+adapter->toString(), E_FILE_LINE); + } + adapter->setDeviceDiscoveryListener(nullptr); + adapter->stopDiscovery(*session); + return JNI_TRUE; + } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e) + return JNI_FALSE; +} + +jint Java_direct_1bt_tinyb_Adapter_discoverAnyDeviceImpl(JNIEnv *env, jobject obj, jint timeoutMS) +{ + try { + HCIAdapter *adapter = getInstance<HCIAdapter>(env, obj); + std::shared_ptr<direct_bt::HCISession> session = adapter->getOpenSession(); + if( nullptr == session ) { + throw BluetoothException("No adapter session: "+adapter->toString(), E_FILE_LINE); + } + if( !session->isOpen() ) { + throw BluetoothException("No open adapter session: "+adapter->toString(), E_FILE_LINE); + } + return adapter->discoverDevices(*session, -1, EUI48_ANY_DEVICE, timeoutMS, static_cast<uint32_t>(EInfoReport::Element::NAME)); + } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e) + return 0; +} + +jobject Java_direct_1bt_tinyb_Adapter_getDiscoveredDevicesImpl(JNIEnv *env, jobject obj) +{ + try { + HCIAdapter *adapter = getInstance<HCIAdapter>(env, obj); + /** + std::function<jobject(JNIEnv*, jclass, jmethodID, HCIDevice*)> ctor_device = [&](JNIEnv *env, jclass clazz, jmethodID clazz_ctor, HCIDevice *elem) { + // Device(final long nativeInstance, final Adapter adptr, final String address, final String name) + jstring addr = from_string_to_jstring(env, elem->getAddressString()); + jstring name = from_string_to_jstring(env, elem->getName()); + jobject object = env->NewObject(clazz, clazz_ctor, (jlong)elem, obj, addr, name); + return object; + }; + return convert_vector_to_jobject<HCIDevice>(env, array, "(JLdirect_bt/tinyb/Adapter;Ljava/lang/String;Ljava/lang/String;)V", ctor_device); + */ + std::vector<std::shared_ptr<HCIDevice>> array = adapter->getDiscoveredDevices(); + return convert_vector_to_jobject(env, array); + } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e) + return nullptr; +} + +jint Java_direct_1bt_tinyb_Adapter_removeDevicesImpl(JNIEnv *env, jobject obj) +{ + try { + HCIAdapter *adapter = getInstance<HCIAdapter>(env, obj); + return adapter->removeDiscoveredDevices(); + } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e) + return 0; +} + diff --git a/java/jni/direct_bt/DBTDevice.cxx b/java/jni/direct_bt/DBTDevice.cxx new file mode 100644 index 00000000..b2887b55 --- /dev/null +++ b/java/jni/direct_bt/DBTDevice.cxx @@ -0,0 +1,78 @@ +/* + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "direct_bt_tinyb_Device.h" + +#include "JNIMem.hpp" +#include "helper_base.hpp" +#include "helper_dbt.hpp" + +#include "direct_bt/HCITypes.hpp" + +using namespace direct_bt; + +void Java_direct_1bt_tinyb_Device_initImpl(JNIEnv *env, jobject obj) +{ + try { + HCIDevice *device = getInstance<HCIDevice>(env, obj); + JavaGlobalObj::check(device->getJavaObject(), E_FILE_LINE); + } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e) +} + +void Java_direct_1bt_tinyb_Device_deleteImpl(JNIEnv *env, jobject obj) +{ + try { + HCIDevice *device = getInstance<HCIDevice>(env, obj); + delete device; + } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e) +} + +jshort Java_direct_1bt_tinyb_Device_getRSSI(JNIEnv *env, jobject obj) +{ + try { + HCIDevice *device = getInstance<HCIDevice>(env, obj); + return device->getRSSI(); + } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e) + return 0; +} + +jshort Java_direct_1bt_tinyb_Device_getTxPower(JNIEnv *env, jobject obj) +{ + try { + HCIDevice *device = getInstance<HCIDevice>(env, obj); + return device->getTxPower(); + } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e) + return 0; +} + +jboolean Java_direct_1bt_tinyb_Device_getConnected(JNIEnv *env, jobject obj) +{ + try { + HCIDevice *device = getInstance<HCIDevice>(env, obj); + (void) device; + return JNI_TRUE; // FIXME + } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e) + return JNI_FALSE; +} diff --git a/java/jni/HCIEvent.cxx b/java/jni/direct_bt/DBTEvent.cxx index b1bc89c5..e9203d48 100644 --- a/java/jni/HCIEvent.cxx +++ b/java/jni/direct_bt/DBTEvent.cxx @@ -23,9 +23,9 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "tinyb_hci_HCIEvent.h" +#include "direct_bt_tinyb_DBTEvent.h" -jobject Java_tinyb_hci_HCIEvent_getType(JNIEnv *env, jobject obj) +jobject Java_direct_1bt_tinyb_DBTEvent_getType(JNIEnv *env, jobject obj) { (void)env; (void)obj; @@ -33,7 +33,7 @@ jobject Java_tinyb_hci_HCIEvent_getType(JNIEnv *env, jobject obj) return NULL; } -jstring Java_tinyb_hci_HCIEvent_getName(JNIEnv *env, jobject obj) +jstring Java_direct_1bt_tinyb_DBTEvent_getName(JNIEnv *env, jobject obj) { (void)env; (void)obj; @@ -41,7 +41,7 @@ jstring Java_tinyb_hci_HCIEvent_getName(JNIEnv *env, jobject obj) return NULL; } -jstring Java_tinyb_hci_HCIEvent_getIdentifier(JNIEnv *env, jobject obj) +jstring Java_direct_1bt_tinyb_DBTEvent_getIdentifier(JNIEnv *env, jobject obj) { (void)env; (void)obj; @@ -49,7 +49,7 @@ jstring Java_tinyb_hci_HCIEvent_getIdentifier(JNIEnv *env, jobject obj) return NULL; } -jboolean Java_tinyb_hci_HCIEvent_executeCallback(JNIEnv *env, jobject obj) +jboolean Java_direct_1bt_tinyb_DBTEvent_executeCallback(JNIEnv *env, jobject obj) { (void)env; (void)obj; @@ -57,7 +57,7 @@ jboolean Java_tinyb_hci_HCIEvent_executeCallback(JNIEnv *env, jobject obj) return JNI_FALSE; } -jboolean Java_tinyb_hci_HCIEvent_hasCallback(JNIEnv *env, jobject obj) +jboolean Java_direct_1bt_tinyb_DBTEvent_hasCallback(JNIEnv *env, jobject obj) { (void)env; (void)obj; @@ -65,9 +65,9 @@ jboolean Java_tinyb_hci_HCIEvent_hasCallback(JNIEnv *env, jobject obj) return JNI_FALSE; } -void Java_tinyb_hci_HCIEvent_init(JNIEnv *env, jobject obj, jobject type, jstring name, - jstring identifier, jobject parent, jobject callback, - jobject arg_data) +void Java_direct_1bt_tinyb_DBTEvent_init(JNIEnv *env, jobject obj, jobject type, jstring name, + jstring identifier, jobject parent, jobject callback, + jobject arg_data) { (void)env; (void)obj; @@ -79,7 +79,7 @@ void Java_tinyb_hci_HCIEvent_init(JNIEnv *env, jobject obj, jobject type, jstrin (void)arg_data; } -void Java_tinyb_hci_HCIEvent_delete(JNIEnv *env, jobject obj) +void Java_direct_1bt_tinyb_DBTEvent_delete(JNIEnv *env, jobject obj) { (void)env; (void)obj; diff --git a/java/jni/HCIGattCharacteristic.cxx b/java/jni/direct_bt/DBTGattCharacteristic.cxx index 0a0c4c07..cae33960 100644 --- a/java/jni/HCIGattCharacteristic.cxx +++ b/java/jni/direct_bt/DBTGattCharacteristic.cxx @@ -23,12 +23,12 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "direct_bt/HCITypes.hpp" - -#include "tinyb_hci_HCIGattCharacteristic.h" +#include "direct_bt_tinyb_GattCharacteristic.h" #include "JNIMem.hpp" #include "helper_base.hpp" +#include "direct_bt/HCITypes.hpp" + using namespace direct_bt; diff --git a/java/jni/HCIDevice.cxx b/java/jni/direct_bt/DBTGattDescriptor.cxx index d143b85d..59410d92 100644 --- a/java/jni/HCIDevice.cxx +++ b/java/jni/direct_bt/DBTGattDescriptor.cxx @@ -23,12 +23,12 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "direct_bt/HCITypes.hpp" - -#include "tinyb_hci_HCIDevice.h" +#include "direct_bt_tinyb_GattDescriptor.h" #include "JNIMem.hpp" #include "helper_base.hpp" +#include "direct_bt/HCITypes.hpp" + using namespace direct_bt; diff --git a/java/jni/HCIGattService.cxx b/java/jni/direct_bt/DBTGattService.cxx index 14dfcbe8..6e0fe141 100644 --- a/java/jni/HCIGattService.cxx +++ b/java/jni/direct_bt/DBTGattService.cxx @@ -23,12 +23,12 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "direct_bt/HCITypes.hpp" - -#include "tinyb_hci_HCIGattService.h" +#include "direct_bt_tinyb_GattService.h" #include "JNIMem.hpp" #include "helper_base.hpp" +#include "direct_bt/HCITypes.hpp" + using namespace direct_bt; diff --git a/java/jni/direct_bt/DBTManager.cxx b/java/jni/direct_bt/DBTManager.cxx new file mode 100644 index 00000000..0c01272d --- /dev/null +++ b/java/jni/direct_bt/DBTManager.cxx @@ -0,0 +1,106 @@ +/* + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "direct_bt_tinyb_Manager.h" + +// #define VERBOSE_ON 1 +#include <dbt_debug.hpp> + +#include "JNIMem.hpp" +#include "helper_base.hpp" +#include "helper_dbt.hpp" + +#include "direct_bt/HCITypes.hpp" + +using namespace direct_bt; + +void Java_direct_1bt_tinyb_Manager_initImpl(JNIEnv *env, jobject obj) +{ + try { + MgmtHandler *manager = &MgmtHandler::get(); // special: static singleton + setInstance<MgmtHandler>(env, obj, manager); + manager->setJavaObject( std::shared_ptr<JavaAnonObj>( new JavaGlobalObj(obj) ) ); + JavaGlobalObj::check(manager->getJavaObject(), E_FILE_LINE); + DBG_PRINT("Java_direct_1bt_tinyb_Manager_init: Manager %s", manager->toString().c_str()); + } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e) +} + +void Java_direct_1bt_tinyb_Manager_deleteImpl(JNIEnv *env, jobject obj) +{ + try { + MgmtHandler *manager = getInstance<MgmtHandler>(env, obj); // special: static singleton + manager->setJavaObject(nullptr); + // delete manager; + (void) manager; + } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e) +} + +static const std::string _adapterClazzCtorArgs("(JLjava/lang/String;Ljava/lang/String;)V"); + +jobject Java_direct_1bt_tinyb_Manager_getDefaultAdapterImpl(JNIEnv *env, jobject obj) +{ + try { + MgmtHandler *manager = getInstance<MgmtHandler>(env, obj); + DBG_PRINT("Java_direct_1bt_tinyb_Manager_getDefaultAdapterImpl: Manager %s", manager->toString().c_str()); + int defAdapterIdx = manager->getDefaultAdapterIdx(); + HCIAdapter * adapter = new HCIAdapter(defAdapterIdx); + if( !adapter->isValid() ) { + delete adapter; + throw BluetoothException("Invalid default adapter "+std::to_string(defAdapterIdx), E_FILE_LINE); + } + if( !adapter->hasDevId() ) { + delete adapter; + throw BluetoothException("Invalid default adapter dev-id "+std::to_string(defAdapterIdx), E_FILE_LINE); + } + std::shared_ptr<direct_bt::HCISession> session = adapter->open(); + if( nullptr == session ) { + delete adapter; + throw BluetoothException("Couldn't open default adapter "+std::to_string(defAdapterIdx), E_FILE_LINE); + } + + // prepare adapter ctor + const jstring addr = from_string_to_jstring(env, adapter->getAddressString()); + const jstring name = from_string_to_jstring(env, adapter->getName()); + const jclass clazz = search_class(env, *adapter); + if( nullptr == clazz ) { + throw InternalError("Adapter class not found: "+HCIAdapter::java_class(), E_FILE_LINE); + } + const jmethodID clazz_ctor = search_method(env, clazz, "<init>", _adapterClazzCtorArgs.c_str(), false); + if( nullptr == clazz_ctor ) { + throw InternalError("Adapter ctor not found: "+HCIAdapter::java_class()+".<init>"+_adapterClazzCtorArgs, E_FILE_LINE); + } + exception_check_raise_and_throw(env, E_FILE_LINE); + jobject jAdapter = env->NewObject(clazz, clazz_ctor, (jlong)adapter, addr, name); + exception_check_raise_and_throw(env, E_FILE_LINE); + JNIGlobalRef::check(jAdapter, E_FILE_LINE); + std::shared_ptr<JavaAnonObj> jAdapterRef = adapter->getJavaObject(); + JavaGlobalObj::check(jAdapterRef, E_FILE_LINE); + + DBG_PRINT("Java_direct_1bt_tinyb_Manager_getDefaultAdapterImpl: New Adapter %s", adapter->toString().c_str()); + return JavaGlobalObj::GetObject(jAdapterRef); + } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e) + return NULL; +} + diff --git a/java/jni/direct_bt/DBTNativeDownlink.cxx b/java/jni/direct_bt/DBTNativeDownlink.cxx new file mode 100644 index 00000000..201d0728 --- /dev/null +++ b/java/jni/direct_bt/DBTNativeDownlink.cxx @@ -0,0 +1,58 @@ +/* + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "direct_bt_tinyb_NativeDownlink.h" + +// #define VERBOSE_ON 1 +#include <dbt_debug.hpp> + +#include "JNIMem.hpp" +#include "helper_base.hpp" +#include "helper_dbt.hpp" + +#include "direct_bt/HCITypes.hpp" + +using namespace direct_bt; + +void Java_direct_1bt_tinyb_NativeDownlink_initNativeJavaObject(JNIEnv *env, jobject obj, jlong nativeInstance) +{ + try { + JavaUplink *javaUplink = castInstance<JavaUplink>(nativeInstance); + std::shared_ptr<JavaGlobalObj> jobjRef( new JavaGlobalObj(obj) ); + javaUplink->setJavaObject( jobjRef ); + JavaGlobalObj::check(javaUplink->getJavaObject(), E_FILE_LINE); + } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e) +} + +void Java_direct_1bt_tinyb_NativeDownlink_clearNativeJavaObject(JNIEnv *env, jobject obj, jlong nativeInstance) +{ + (void)obj; + try { + JavaUplink *javaUplink = castInstance<JavaUplink>(nativeInstance); + DBG_PRINT("Java_direct_1bt_tinyb_NativeDownlink_clearNativeJavaObject %s", javaUplink->toString().c_str()); + javaUplink->setJavaObject(nullptr); + } CATCH_EXCEPTION_AND_RAISE_JAVA(env, e) +} + diff --git a/java/jni/HCIAdapter.cxx b/java/jni/direct_bt/DBTObject.cxx index afb420fc..74f40e8a 100644 --- a/java/jni/HCIAdapter.cxx +++ b/java/jni/direct_bt/DBTObject.cxx @@ -23,12 +23,12 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "direct_bt/HCITypes.hpp" - -#include "tinyb_hci_HCIAdapter.h" +// #include "direct_bt_tinyb_DBTObject.h" #include "JNIMem.hpp" #include "helper_base.hpp" +#include "direct_bt/HCITypes.hpp" + using namespace direct_bt; diff --git a/java/jni/direct_bt/helper_dbt.cxx b/java/jni/direct_bt/helper_dbt.cxx new file mode 100644 index 00000000..b3431edc --- /dev/null +++ b/java/jni/direct_bt/helper_dbt.cxx @@ -0,0 +1,65 @@ +/* + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <jni.h> +#include <memory> +#include <stdexcept> +#include <vector> + +#include "helper_dbt.hpp" + +using namespace direct_bt; + +jclass direct_bt::search_class(JNIEnv *env, JavaUplink &object) +{ + return search_class(env, object.get_java_class().c_str()); +} + +#if 0 + +jobject direct_bt::convert_vector_to_jobject(JNIEnv *env, std::vector<std::shared_ptr<JavaUplink>>& array) +{ + unsigned int array_size = array.size(); + + jmethodID arraylist_add; + jobject result = get_new_arraylist(env, array_size, &arraylist_add); + + if (0 == array_size) { + return result; + } + + for (unsigned int i = 0; i < array_size; ++i) { + std::shared_ptr<JavaUplink> elem = array.at(i); + std::shared_ptr<JNIGlobalRef> objref = elem->getJavaObject(); + if ( nullptr == objref ) { + throw InternalError("JavaUplink element of array has no valid java-object: "+elem->toString(), E_FILE_LINE); + } + env->CallBooleanMethod(result, arraylist_add, objref->get()); + } + return result; +} + +#endif + diff --git a/java/jni/direct_bt/helper_dbt.hpp b/java/jni/direct_bt/helper_dbt.hpp new file mode 100644 index 00000000..2f3d265f --- /dev/null +++ b/java/jni/direct_bt/helper_dbt.hpp @@ -0,0 +1,113 @@ +/* + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef HELPER_DBT_HPP_ +#define HELPER_DBT_HPP_ + +#include "JNIMem.hpp" +#include "helper_base.hpp" + +#include "direct_bt/JavaAccess.hpp" +#include "direct_bt/BasicTypes.hpp" + +namespace direct_bt { + + class JavaGlobalObj : public JavaAnonObj { + private: + JNIGlobalRef javaObjectRef; + + public: + static inline void check(const std::shared_ptr<JavaAnonObj> & shref, const char* file, int line) { + if( nullptr == shref ) { + throw direct_bt::RuntimeException("JavaGlobalObj::check: Null shared-JavaAnonObj", file, line); + } + const jobject obj = static_cast<const JavaGlobalObj*>(shref.get())->getObject(); + if( nullptr == obj ) { + throw direct_bt::RuntimeException("JavaGlobalObj::check: Null object", file, line); + } + } + JavaGlobalObj(jobject obj) : javaObjectRef(obj) { } + ~JavaGlobalObj() override { } + + std::string toString() const override { + const uint64_t ref = (uint64_t)(void*)javaObjectRef.getObject(); + return "JavaGlobalObj["+uint64HexString(ref, true)+"]"; + } + + JNIGlobalRef & getJavaObject() { return javaObjectRef; } + + /* Provides access to the stored GlobalRef as an jobject. */ + jobject getObject() const { return javaObjectRef.getObject(); } + /* Provides access to the stored GlobalRef as a jclass. */ + jclass getClass() const { return javaObjectRef.getClass(); } + + /* Provides access to the stored GlobalRef as an jobject. */ + static jobject GetObject(const std::shared_ptr<JavaAnonObj> & shref) { + return static_cast<JavaGlobalObj*>(shref.get())->getObject(); + } + + /* Provides access to the stored GlobalRef as a jclass. */ + static jclass GetClass(const std::shared_ptr<JavaAnonObj> & shref) { + return static_cast<JavaGlobalObj*>(shref.get())->getClass(); + } + }; + + + jclass search_class(JNIEnv *env, JavaUplink &object); + +#if 0 + + jobject convert_vector_to_jobject(JNIEnv *env, std::vector<std::shared_ptr<JavaUplink>>& array); + +#else + + template <typename T> + jobject convert_vector_to_jobject(JNIEnv *env, std::vector<std::shared_ptr<T>>& array) + { + unsigned int array_size = array.size(); + + jmethodID arraylist_add; + jobject result = get_new_arraylist(env, array_size, &arraylist_add); + + if (0 == array_size) { + return result; + } + + for (unsigned int i = 0; i < array_size; ++i) { + std::shared_ptr<T> elem = array.at(i); + std::shared_ptr<JavaAnonObj> objref = elem->getJavaObject(); + if ( nullptr == objref ) { + throw InternalError("JavaUplink element of array has no valid java-object: "+elem->toString(), E_FILE_LINE); + } + env->CallBooleanMethod(result, arraylist_add, JavaGlobalObj::GetObject(objref)); + } + return result; + } + +#endif + +} // namespace direct_bt + +#endif /* HELPER_DBT_HPP_ */ diff --git a/java/jni/helper_base.cxx b/java/jni/helper_base.cxx index 2c0c23e6..dd3dcf54 100644 --- a/java/jni/helper_base.cxx +++ b/java/jni/helper_base.cxx @@ -31,7 +31,9 @@ #include <stdexcept> #include <vector> -#include "helper_tinyb.hpp" +#include "helper_base.hpp" + +#define JAVA_MAIN_PACKAGE "org/tinyb" jfieldID getInstanceField(JNIEnv *env, jobject obj) { @@ -144,6 +146,11 @@ std::string from_jstring_to_string(JNIEnv *env, jstring str) return string_to_write; } +jstring from_string_to_jstring(JNIEnv *env, const std::string & str) +{ + return env->NewStringUTF(str.c_str()); +} + jobject get_bluetooth_type(JNIEnv *env, const char *field_name) { jclass b_type_enum = search_class(env, JAVA_MAIN_PACKAGE "/BluetoothType"); @@ -182,6 +189,10 @@ void raise_java_runtime_exception(JNIEnv *env, std::runtime_error &e) env->ThrowNew(env->FindClass("java/lang/RuntimeException"), e.what()); } +void raise_java_runtime_exception(JNIEnv *env, direct_bt::RuntimeException &e) { + env->ThrowNew(env->FindClass("java/lang/RuntimeException"), e.what()); +} + void raise_java_oom_exception(JNIEnv *env, std::bad_alloc &e) { env->ThrowNew(env->FindClass("java/lang/OutOfMemoryException"), e.what()); @@ -192,4 +203,18 @@ void raise_java_invalid_arg_exception(JNIEnv *env, std::invalid_argument &e) env->ThrowNew(env->FindClass("java/lang/IllegalArgumentException"), e.what()); } +void raise_java_bluetooth_exception(JNIEnv *env, direct_bt::BluetoothException &e) +{ + env->ThrowNew(env->FindClass("org/tinyb/BluetoothException"), e.what()); +} +void exception_check_raise_and_throw(JNIEnv *env, const char* file, int line) +{ + if( env->ExceptionCheck() ) { + env->ExceptionDescribe(); + jthrowable e = env->ExceptionOccurred(); + env->ExceptionClear(); + env->Throw(e); + throw direct_bt::RuntimeException("Java exception occurred and forwarded.", file, line); + } +} diff --git a/java/jni/helper_base.hpp b/java/jni/helper_base.hpp index 153faa9b..4cbda995 100644 --- a/java/jni/helper_base.hpp +++ b/java/jni/helper_base.hpp @@ -26,10 +26,15 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#pragma once +#ifndef HELPER_BASE_HPP_ +#define HELPER_BASE_HPP_ #include <vector> #include <memory> +#include <functional> +#include <jni.h> + +#include "BasicTypes.hpp" jfieldID getInstanceField(JNIEnv *env, jobject obj); @@ -41,10 +46,20 @@ jfieldID search_field(JNIEnv *env, jclass clazz, const char *field_name, const char *type, bool is_static); bool from_jboolean_to_bool(jboolean val); std::string from_jstring_to_string(JNIEnv *env, jstring str); +jstring from_string_to_jstring(JNIEnv *env, const std::string & str); jobject get_bluetooth_type(JNIEnv *env, const char *field_name); jobject get_new_arraylist(JNIEnv *env, unsigned int size, jmethodID *add); template <typename T> +T *castInstance(jlong instance) +{ + T *t = reinterpret_cast<T *>(instance); + if (t == nullptr) + throw std::runtime_error("Trying to cast null object"); + return t; +} + +template <typename T> T *getInstance(JNIEnv *env, jobject obj) { jlong instance = env->GetLongField(obj, getInstanceField(env, obj)); @@ -111,7 +126,58 @@ jobject convert_vector_to_jobject(JNIEnv *env, std::vector<std::unique_ptr<T>>& return result; } +template <typename T> +jobject convert_vector_to_jobject(JNIEnv *env, std::vector<std::shared_ptr<T>>& array, + const char *ctor_prototype, std::function<jobject(JNIEnv*, jclass, jmethodID, T*)> ctor) +{ + unsigned int array_size = array.size(); + + jmethodID arraylist_add; + jobject result = get_new_arraylist(env, array_size, &arraylist_add); + + if (array_size == 0) + { + return result; + } + + jclass clazz = search_class(env, T::java_class().c_str()); + jmethodID clazz_ctor = search_method(env, clazz, "<init>", ctor_prototype, false); + + for (unsigned int i = 0; i < array_size; ++i) + { + T *elem = array.at(i).get(); + jobject object = ctor(env, clazz, clazz_ctor, elem); + if (!object) + { + throw std::runtime_error("cannot create instance of class\n"); + } + env->CallBooleanMethod(result, arraylist_add, object); + } + return result; +} + void raise_java_exception(JNIEnv *env, std::exception &e); void raise_java_runtime_exception(JNIEnv *env, std::runtime_error &e); +void raise_java_runtime_exception(JNIEnv *env, direct_bt::RuntimeException &e); void raise_java_oom_exception(JNIEnv *env, std::bad_alloc &e); void raise_java_invalid_arg_exception(JNIEnv *env, std::invalid_argument &e); +void raise_java_bluetooth_exception(JNIEnv *env, direct_bt::BluetoothException &e); + +void exception_check_raise_and_throw(JNIEnv *env, const char* file, int line); + +#define CATCH_EXCEPTION_AND_RAISE_JAVA(env, e) \ + catch (std::bad_alloc &e) { \ + raise_java_oom_exception(env, e); \ +} catch (direct_bt::BluetoothException &e) { \ + raise_java_bluetooth_exception(env, e); \ +} catch (direct_bt::RuntimeException &e) { \ + raise_java_runtime_exception(env, e); \ +} catch (std::runtime_error &e) { \ + raise_java_runtime_exception(env, e); \ +} catch (std::invalid_argument &e) { \ + raise_java_invalid_arg_exception(env, e); \ +} catch (std::exception &e) { \ + raise_java_exception(env, e); \ +} + +#endif /* HELPER_BASE_HPP_ */ diff --git a/java/jni/tinyb/CMakeLists.txt b/java/jni/tinyb/CMakeLists.txt new file mode 100644 index 00000000..a2bfb5a7 --- /dev/null +++ b/java/jni/tinyb/CMakeLists.txt @@ -0,0 +1,54 @@ +find_package(JNI REQUIRED) + +if (JNI_FOUND) + message (STATUS "JNI_INCLUDE_DIRS=${JNI_INCLUDE_DIRS}") + message (STATUS "JNI_LIBRARIES=${JNI_LIBRARIES}") +endif (JNI_FOUND) + +set (tinyb_LIB_INCLUDE_DIRS + ${PROJECT_SOURCE_DIR}/api + ${PROJECT_SOURCE_DIR}/api/direct_bt + ${PROJECT_SOURCE_DIR}/api/tinyb + ${PROJECT_SOURCE_DIR}/include + ${PROJECT_SOURCE_DIR}/java/jni +) + +include_directories( + ${JNI_INCLUDE_DIRS} + ${tinyb_LIB_INCLUDE_DIRS} + ${JNI_HEADER_PATH} +) + +set (tinyb_JNI_SRCS + ${PROJECT_SOURCE_DIR}/src/direct_bt/BasicTypes.cpp + ${PROJECT_SOURCE_DIR}/java/jni/JNIMem.cxx + ${PROJECT_SOURCE_DIR}/java/jni/helper_base.cxx + ${PROJECT_SOURCE_DIR}/java/jni/BluetoothFactory.cxx + ${PROJECT_SOURCE_DIR}/java/jni/BluetoothUtils.cxx + ${PROJECT_SOURCE_DIR}/java/jni/tinyb/helper_tinyb.cxx + ${PROJECT_SOURCE_DIR}/java/jni/tinyb/DBusAdapter.cxx + ${PROJECT_SOURCE_DIR}/java/jni/tinyb/DBusDevice.cxx + ${PROJECT_SOURCE_DIR}/java/jni/tinyb/DBusEvent.cxx + ${PROJECT_SOURCE_DIR}/java/jni/tinyb/DBusGattCharacteristic.cxx + ${PROJECT_SOURCE_DIR}/java/jni/tinyb/DBusGattDescriptor.cxx + ${PROJECT_SOURCE_DIR}/java/jni/tinyb/DBusGattService.cxx + ${PROJECT_SOURCE_DIR}/java/jni/tinyb/DBusManager.cxx + ${PROJECT_SOURCE_DIR}/java/jni/tinyb/DBusObject.cxx +) + +set (CMAKE_SHARED_LINKER_FLAGS "-Wl,--as-needed") + +add_library (javatinyb SHARED ${tinyb_JNI_SRCS}) +target_link_libraries(javatinyb ${JNI_LIBRARIES} tinyb) + +set_target_properties( + javatinyb + PROPERTIES + SOVERSION ${tinyb_VERSION_MAJOR} + VERSION ${tinyb_VERSION_STRING} + CXX_STANDARD 11 + COMPILE_FLAGS "-Wall -Wextra" +) + +install(TARGETS javatinyb LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) + diff --git a/java/jni/DBusAdapter.cxx b/java/jni/tinyb/DBusAdapter.cxx index 9f43c4b8..9f43c4b8 100644 --- a/java/jni/DBusAdapter.cxx +++ b/java/jni/tinyb/DBusAdapter.cxx diff --git a/java/jni/DBusDevice.cxx b/java/jni/tinyb/DBusDevice.cxx index 6a833356..6a833356 100644 --- a/java/jni/DBusDevice.cxx +++ b/java/jni/tinyb/DBusDevice.cxx diff --git a/java/jni/DBusEvent.cxx b/java/jni/tinyb/DBusEvent.cxx index 14b6431c..14b6431c 100644 --- a/java/jni/DBusEvent.cxx +++ b/java/jni/tinyb/DBusEvent.cxx diff --git a/java/jni/DBusGattCharacteristic.cxx b/java/jni/tinyb/DBusGattCharacteristic.cxx index 43ac754f..43ac754f 100644 --- a/java/jni/DBusGattCharacteristic.cxx +++ b/java/jni/tinyb/DBusGattCharacteristic.cxx diff --git a/java/jni/DBusGattDescriptor.cxx b/java/jni/tinyb/DBusGattDescriptor.cxx index 2118205c..2118205c 100644 --- a/java/jni/DBusGattDescriptor.cxx +++ b/java/jni/tinyb/DBusGattDescriptor.cxx diff --git a/java/jni/DBusGattService.cxx b/java/jni/tinyb/DBusGattService.cxx index 0ab089f2..0ab089f2 100644 --- a/java/jni/DBusGattService.cxx +++ b/java/jni/tinyb/DBusGattService.cxx diff --git a/java/jni/DBusManager.cxx b/java/jni/tinyb/DBusManager.cxx index 1680e866..1680e866 100644 --- a/java/jni/DBusManager.cxx +++ b/java/jni/tinyb/DBusManager.cxx diff --git a/java/jni/DBusObject.cxx b/java/jni/tinyb/DBusObject.cxx index 8e3b93a2..8e3b93a2 100644 --- a/java/jni/DBusObject.cxx +++ b/java/jni/tinyb/DBusObject.cxx diff --git a/java/jni/helper_tinyb.cxx b/java/jni/tinyb/helper_tinyb.cxx index 865d55e5..c20b5933 100644 --- a/java/jni/helper_tinyb.cxx +++ b/java/jni/tinyb/helper_tinyb.cxx @@ -33,76 +33,78 @@ #include "helper_tinyb.hpp" -jclass search_class(JNIEnv *env, tinyb::BluetoothObject &object) +using namespace tinyb; + +jclass search_class(JNIEnv *env, BluetoothObject &object) { return search_class(env, object.get_java_class().c_str()); } -tinyb::BluetoothType from_int_to_btype(int type) +BluetoothType from_int_to_btype(int type) { - tinyb::BluetoothType result = tinyb::BluetoothType::NONE; + BluetoothType result = BluetoothType::NONE; switch (type) { case 0: - result = tinyb::BluetoothType::NONE; + result = BluetoothType::NONE; break; case 1: - result = tinyb::BluetoothType::ADAPTER; + result = BluetoothType::ADAPTER; break; case 2: - result = tinyb::BluetoothType::DEVICE; + result = BluetoothType::DEVICE; break; case 3: - result = tinyb::BluetoothType::GATT_SERVICE; + result = BluetoothType::GATT_SERVICE; break; case 4: - result = tinyb::BluetoothType::GATT_CHARACTERISTIC; + result = BluetoothType::GATT_CHARACTERISTIC; break; case 5: - result = tinyb::BluetoothType::GATT_CHARACTERISTIC; + result = BluetoothType::GATT_CHARACTERISTIC; break; default: - result = tinyb::BluetoothType::NONE; + result = BluetoothType::NONE; break; } return result; } -tinyb::TransportType from_int_to_transport_type(int type) +TransportType from_int_to_transport_type(int type) { - tinyb::TransportType result = tinyb::TransportType::AUTO; + TransportType result = TransportType::AUTO; switch (type) { case 0: - result = tinyb::TransportType::AUTO; + result = TransportType::AUTO; break; case 1: - result = tinyb::TransportType::BREDR; + result = TransportType::BREDR; break; case 2: - result = tinyb::TransportType::LE; + result = TransportType::LE; break; default: - result = tinyb::TransportType::AUTO; + result = TransportType::AUTO; break; } return result; } -void raise_java_bluetooth_exception(JNIEnv *env, tinyb::BluetoothException &e) +void raise_java_bluetooth_exception(JNIEnv *env, BluetoothException &e) { env->ThrowNew(env->FindClass("org/tinyb/BluetoothException"), e.what()); } diff --git a/java/jni/helper_tinyb.hpp b/java/jni/tinyb/helper_tinyb.hpp index f1873a7f..d91051c4 100644 --- a/java/jni/helper_tinyb.hpp +++ b/java/jni/tinyb/helper_tinyb.hpp @@ -32,8 +32,12 @@ #include "tinyb/BluetoothObject.hpp" #include "tinyb/BluetoothException.hpp" -jclass search_class(JNIEnv *env, tinyb::BluetoothObject &object); -tinyb::BluetoothType from_int_to_btype(int type); -tinyb::TransportType from_int_to_transport_type(int type); +namespace tinyb { -void raise_java_bluetooth_exception(JNIEnv *env, tinyb::BluetoothException &e); + jclass search_class(JNIEnv *env, BluetoothObject &object); + BluetoothType from_int_to_btype(int type); + TransportType from_int_to_transport_type(int type); + + void raise_java_bluetooth_exception(JNIEnv *env, BluetoothException &e); + +} // namespace tinyb diff --git a/java/org/tinyb/BluetoothAdapter.java b/java/org/tinyb/BluetoothAdapter.java index 95d2e6d0..2b55cf75 100644 --- a/java/org/tinyb/BluetoothAdapter.java +++ b/java/org/tinyb/BluetoothAdapter.java @@ -242,6 +242,12 @@ public interface BluetoothAdapter extends BluetoothObject public boolean getDiscovering(); /** + * Sets the {@link BluetoothDeviceDiscoveryListener} for the respective device discovery events. + * @param listener A {@link BluetoothDeviceDiscoveryListener} instance, or {@code null} to disable notifications. + */ + public void setDeviceDiscoveryListener(final BluetoothDeviceDiscoveryListener listener); + + /** * Enables notifications for the discovering property and calls run function of the * BluetoothNotification object. * @param callback A BluetoothNotification<Boolean> object. Its run function will be called diff --git a/java/org/tinyb/BluetoothDeviceDiscoveryListener.java b/java/org/tinyb/BluetoothDeviceDiscoveryListener.java new file mode 100644 index 00000000..737f47b9 --- /dev/null +++ b/java/org/tinyb/BluetoothDeviceDiscoveryListener.java @@ -0,0 +1,42 @@ +/** + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2020 Gothel Software e.K. + * Copyright (c) 2020 ZAFENA AB + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package org.tinyb; + +/** + * {@link BluetoothDevice} listener for the respective {@link BluetoothDevice} discovery events: Added, updated and removed. + * <p> + * A listener instance may be attached to a {@link BluetoothAdapter} via + * {@link BluetoothAdapter#setDeviceDiscoveryListener(BluetoothDeviceDiscoveryListener)}. + * </p> + */ +public interface BluetoothDeviceDiscoveryListener { + /** A {@link BluetoothDevice} has been newly discovered. */ + public void deviceAdded(final BluetoothAdapter adapter, final BluetoothDevice device); + /** An already discovered {@link BluetoothDevice} has been updated. */ + public void deviceUpdated(final BluetoothAdapter adapter, final BluetoothDevice device); + /** An already discovered {@link BluetoothDevice} has been removed or lost. */ + public void deviceRemoved(final BluetoothAdapter adapter, final BluetoothDevice device); +}; diff --git a/java/org/tinyb/BluetoothFactory.java b/java/org/tinyb/BluetoothFactory.java index 8f01db15..38306a16 100644 --- a/java/org/tinyb/BluetoothFactory.java +++ b/java/org/tinyb/BluetoothFactory.java @@ -39,12 +39,12 @@ public class BluetoothFactory { /** * Name of the native implementation native library basename: {@value} */ - public static final String ImplNativeLibBasename = "tinyb"; + public static final String ImplNativeLibBasename = "direct_bt"; // "tinyb"; /** * Name of the Jave native library basename: {@value} */ - public static final String JavaNativeLibBasename = "javatinyb"; + public static final String JavaNativeLibBasename = "javadirect_bt"; // "javatinyb"; /** * Manifest's {@link Attributes.Name#SPECIFICATION_VERSION} or {@code null} if not available. @@ -138,12 +138,12 @@ public class BluetoothFactory { public static final String DBusFactoryImplClassName = "tinyb.dbus.DBusManager"; /** - * Fully qualified factory class name for native HCI implementation: {@value} + * Fully qualified factory class name for direct_bt implementation: {@value} * <p> * This value is exposed for convenience, user implementations are welcome. * </p> */ - public static final String HCIFactoryImplClassName = "tinyb.hci.HCIManager"; + public static final String DirectBTFactoryImplClassName = "direct_bt.tinyb.Manager"; /** * Returns an initialized BluetoothManager instance using the given {@code factoryImplClass}. @@ -187,7 +187,7 @@ public class BluetoothFactory { * @throws InvocationTargetException * @throws ClassNotFoundException * @see {@link #DBusFactoryImplClassName} - * @see {@link #HCIFactoryImplClassName} + * @see {@link #DirectBTFactoryImplClassName} */ public static synchronized BluetoothManager getBluetoothManager(final String factoryImplClassName) throws BluetoothException, NoSuchMethodException, SecurityException, diff --git a/java/org/tinyb/BluetoothManager.java b/java/org/tinyb/BluetoothManager.java index ec1de2d7..b7bec3cb 100644 --- a/java/org/tinyb/BluetoothManager.java +++ b/java/org/tinyb/BluetoothManager.java @@ -181,4 +181,13 @@ public interface BluetoothManager * @return TRUE if discovery is running */ public boolean getDiscovering() throws BluetoothException; + + /** + * Release the native memory associated with this object and all related Bluetooth resources. + * The object should not be used following a call to close + * <p> + * Shutdown method is intended to allow a clean Bluetooth state at program exist. + * </p> + */ + public void shutdown(); } diff --git a/java/jni/HCIGattDescriptor.cxx b/java/org/tinyb/BluetoothUtils.java index cefc6b4d..e7a0276b 100644 --- a/java/jni/HCIGattDescriptor.cxx +++ b/java/org/tinyb/BluetoothUtils.java @@ -1,4 +1,4 @@ -/* +/** * Author: Sven Gothel <[email protected]> * Copyright (c) 2020 Gothel Software e.K. * Copyright (c) 2020 ZAFENA AB @@ -22,13 +22,13 @@ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +package org.tinyb; -#include "direct_bt/HCITypes.hpp" +public class BluetoothUtils { -#include "tinyb_hci_HCIGattDescriptor.h" - -#include "JNIMem.hpp" -#include "helper_base.hpp" - -using namespace direct_bt; + /** + * Returns current monotonic time in milliseconds. + */ + public static native long getCurrentMilliseconds(); +} diff --git a/java/tinyb/dbus/DBusAdapter.java b/java/tinyb/dbus/DBusAdapter.java index 695677fe..973d3e8d 100644 --- a/java/tinyb/dbus/DBusAdapter.java +++ b/java/tinyb/dbus/DBusAdapter.java @@ -35,6 +35,7 @@ import java.util.UUID; import org.tinyb.BluetoothAdapter; import org.tinyb.BluetoothDevice; +import org.tinyb.BluetoothDeviceDiscoveryListener; import org.tinyb.BluetoothException; import org.tinyb.BluetoothManager; import org.tinyb.BluetoothNotification; @@ -148,6 +149,11 @@ public class DBusAdapter extends DBusObject implements BluetoothAdapter public native boolean getDiscovering(); @Override + public void setDeviceDiscoveryListener(final BluetoothDeviceDiscoveryListener l) { + throw new UnsupportedOperationException(); // FIXME + } + + @Override public native void enableDiscoveringNotifications(BluetoothNotification<Boolean> callback); @Override diff --git a/java/tinyb/dbus/DBusManager.java b/java/tinyb/dbus/DBusManager.java index 2b5efe65..bfcd5e4b 100644 --- a/java/tinyb/dbus/DBusManager.java +++ b/java/tinyb/dbus/DBusManager.java @@ -134,4 +134,9 @@ public class DBusManager implements BluetoothManager { delete(); } + + @Override + public void shutdown() { + delete(); + } } diff --git a/java/tinyb/hci/HCIAdapter.java b/java/tinyb/hci/HCIAdapter.java deleted file mode 100644 index 71c9d818..00000000 --- a/java/tinyb/hci/HCIAdapter.java +++ /dev/null @@ -1,199 +0,0 @@ -/** - * Author: Sven Gothel <[email protected]> - * Copyright (c) 2020 Gothel Software e.K. - * Copyright (c) 2020 ZAFENA AB - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -package tinyb.hci; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.UUID; - -import org.tinyb.BluetoothAdapter; -import org.tinyb.BluetoothDevice; -import org.tinyb.BluetoothException; -import org.tinyb.BluetoothManager; -import org.tinyb.BluetoothNotification; -import org.tinyb.BluetoothType; -import org.tinyb.TransportType; - -public class HCIAdapter extends HCIObject implements BluetoothAdapter -{ - private final String address; - private final String name; - - /* pp */ HCIAdapter(final String address, final String name) - { - super(compHash(address, name)); - this.address = address; - this.name = name; - } - - @Override - public boolean equals(final Object obj) - { - if (obj == null || !(obj instanceof HCIDevice)) { - return false; - } - final HCIAdapter other = (HCIAdapter)obj; - return address.equals(other.address) && name.equals(other.name); - } - - @Override - public String getAddress() { return address; } - - @Override - public String getName() { return name; } - - public String getInterfaceName() { - throw new UnsupportedOperationException(); // FIXME - } - - @Override - public native BluetoothType getBluetoothType(); - - @Override - public native BluetoothAdapter clone(); - - static BluetoothType class_type() { return BluetoothType.ADAPTER; } - - @Override - public BluetoothDevice find(final String name, final String address, final long timeoutMS) { - final BluetoothManager manager = HCIManager.getBluetoothManager(); - return (BluetoothDevice) manager.find(BluetoothType.DEVICE, name, address, this, timeoutMS); - } - - @Override - public BluetoothDevice find(final String name, final String address) { - return find(name, address, 0); - } - - /* D-Bus method calls: */ - - @Override - public native boolean startDiscovery() throws BluetoothException; - - @Override - public native boolean stopDiscovery() throws BluetoothException; - - @Override - public native List<BluetoothDevice> getDevices(); - - @Override - public native int removeDevices() throws BluetoothException; - - /* D-Bus property accessors: */ - - @Override - public native String getAlias(); - - @Override - public native void setAlias(String value); - - @Override - public native long getBluetoothClass(); - - @Override - public native boolean getPowered(); - - @Override - public native void enablePoweredNotifications(BluetoothNotification<Boolean> callback); - - @Override - public native void disablePoweredNotifications(); - - @Override - public native void setPowered(boolean value); - - @Override - public native boolean getDiscoverable(); - - @Override - public native void enableDiscoverableNotifications(BluetoothNotification<Boolean> callback); - - @Override - public native void disableDiscoverableNotifications(); - - @Override - public native void setDiscoverable(boolean value); - - @Override - public native long getDiscoverableTimeout(); - - @Override - public native void setDiscoverableTimout(long value); - - @Override - public native BluetoothDevice connectDevice(String address, String addressType); - - @Override - public native boolean getPairable(); - - @Override - public native void enablePairableNotifications(BluetoothNotification<Boolean> callback); - - @Override - public native void disablePairableNotifications(); - - @Override - public native void setPairable(boolean value); - - @Override - public native long getPairableTimeout(); - - @Override - public native void setPairableTimeout(long value); - - @Override - public native boolean getDiscovering(); - - @Override - public native void enableDiscoveringNotifications(BluetoothNotification<Boolean> callback); - - @Override - public native void disableDiscoveringNotifications(); - - @Override - public native String[] getUUIDs(); - - @Override - public native String getModalias(); - - @Override - public void setDiscoveryFilter(final List<UUID> uuids, final int rssi, final int pathloss, final TransportType transportType) { - final List<String> uuidsFmt = new ArrayList<>(uuids.size()); - for (final UUID uuid : uuids) { - uuidsFmt.add(uuid.toString()); - } - setDiscoveryFilter(uuidsFmt, rssi, pathloss, transportType.ordinal()); - } - - public void setRssiDiscoveryFilter(final int rssi) { - setDiscoveryFilter(Collections.EMPTY_LIST, rssi, 0, TransportType.AUTO); - } - - private native void delete(); - - private native void setDiscoveryFilter(List<String> uuids, int rssi, int pathloss, int transportType); -} |