26 package jau.direct_bt;
 
   28 import java.lang.ref.WeakReference;
 
   29 import java.util.ArrayList;
 
   30 import java.util.Iterator;
 
   31 import java.util.List;
 
   32 import java.util.concurrent.atomic.AtomicBoolean;
 
   33 import java.util.concurrent.atomic.AtomicInteger;
 
   34 import java.util.concurrent.atomic.AtomicReference;
 
   61      static final boolean PRINT_DEVICE_LISTS = 
false;
 
   63     private static AtomicInteger globThreadID = 
new AtomicInteger(0);
 
   64     private static int discoverTimeoutMS = 100;
 
   66     private final int dev_id;
 
   71     private final String name;
 
   77     private final Object discoveryLock = 
new Object();
 
   78     private final Object discoveredDevicesLock = 
new Object();
 
   80     private final AtomicBoolean isClosing = 
new AtomicBoolean(
false);
 
   82     private final AtomicBoolean powered_state = 
new AtomicBoolean(
false); 
 
   83     private final AtomicBoolean isDiscoverable = 
new AtomicBoolean(
false); 
 
   85     private final AtomicReference<ScanType> currentMetaScanType = 
new AtomicReference<ScanType>(
ScanType.
NONE); 
 
   87     private final List<WeakReference<BTDevice>> discoveredDevices = 
new ArrayList<WeakReference<BTDevice>>();
 
   90                         final byte byteAddress[],
 
   91                         final byte byteAddressType,
 
   92                         final String name, 
final int dev_id)
 
   94         super(nativeInstance, compHash(java.util.Arrays.hashCode(byteAddress), 31+byteAddressType));
 
   98         this.visibleAddressAndType = addressAndType;
 
  111         if( !isClosing.compareAndSet(
false, 
true) ) {
 
  120         for(
final Iterator<BTDevice> 
id = devices.iterator(); 
id.hasNext(); ) {
 
  129         mngr.removeAdapter(
this); 
 
  134     private final void poweredOff() {
 
  135         powered_state.set(
false);
 
  145         if (obj == 
null || !(obj instanceof 
DBTAdapter)) {
 
  149         return dev_id == other.dev_id && addressAndType.
equals(other.addressAndType);
 
  171         return findDeviceInCache(name, addressAndType);
 
  176         return find(name, addressAndType, 0);
 
  181     private final native 
boolean isDeviceWhitelistedImpl(
final byte[] address, 
byte address_type);
 
  186                                         final short conn_interval_min, 
final short conn_interval_max,
 
  187                                         final short conn_latency, 
final short timeout) {
 
  189                                     conn_interval_min, conn_interval_max, conn_latency, timeout);
 
  191     private native 
boolean addDeviceToWhitelistImpl1(
final byte[] address, 
final byte address_type, 
final int ctype,
 
  192                                         final short conn_interval_min, 
final short conn_interval_max,
 
  193                                         final short conn_latency, 
final short timeout);
 
  200     private native 
boolean addDeviceToWhitelistImpl2(
final byte[] address, 
final byte address_type, 
final int ctype);
 
  204         return removeDeviceFromWhitelistImpl(addressAndType.
address.
b, addressAndType.
type.
value);
 
  206     private native 
boolean removeDeviceFromWhitelistImpl(
final byte[] address, 
final byte address_type);
 
  215         return currentMetaScanType.
get();
 
  221             return "Adapter" + 
"\u271D" + 
"["+addressAndType+
", '"+name+
"', id "+dev_id+
"]";
 
  223         return toStringImpl();
 
  230     private native String toStringImpl();
 
  239     private native 
byte resetImpl();
 
  254     private native 
BTDevice connectDeviceImpl(
byte[] address, 
byte addressType);
 
  281         return startDiscovery(keepAlive, le_scan_active, (
short)24, (
short)24, (
byte)0);
 
  285                                         final short le_scan_interval, 
final short le_scan_window,
 
  287         synchronized( discoveryLock ) {
 
  290             removeDiscoveredDevicesImpl2j();
 
  291             final HCIStatusCode res = 
HCIStatusCode.
get( startDiscoveryImpl(keepAlive, le_scan_active, le_scan_interval, le_scan_window, filter_policy) ); 
 
  292             if( PRINT_DEVICE_LISTS || DEBUG ) {
 
  299     private native 
byte startDiscoveryImpl(
final boolean keepAlive, 
final boolean le_scan_active,
 
  300                                            final short le_scan_interval, 
final short le_scan_window,
 
  305         synchronized( discoveryLock ) {
 
  308             if( PRINT_DEVICE_LISTS || DEBUG ) {
 
  315     private native 
byte stopDiscoveryImpl() throws 
BTException;
 
  318     private native List<
BTDevice> getDiscoveredDevicesImpl();
 
  322         final int cj = removeDiscoveredDevicesImpl2j();
 
  323         final int cn = removeDiscoveredDevicesImpl1();
 
  326                 System.err.println(
"DBTAdapter::removeDevices: Unexpected discovered device count: Native "+cn+
", callback "+cj);
 
  331     private native 
int removeDiscoveredDevicesImpl1() throws 
BTException;
 
  332     private 
int removeDiscoveredDevicesImpl2j() {
 
  333         synchronized(discoveredDevicesLock) {
 
  334             final int n = discoveredDevices.size();
 
  335             discoveredDevices.clear();
 
  339      boolean removeDiscoveredDevice(
final BTDevice device) {
 
  340         return removeDiscoveredDeviceImpl2j( device.getAddressAndType() );
 
  345         final boolean cj = removeDiscoveredDeviceImpl2j(addressAndType);
 
  346         final boolean cn = removeDiscoveredDeviceImpl1(addressAndType.
address.
b, addressAndType.
type.
value);
 
  349                 System.err.println(
"DBTAdapter::removeDevices("+addressAndType+
"): Unexpected discovered device count: Native "+cn+
", callback "+cj);
 
  354     private native 
boolean removeDiscoveredDeviceImpl1(
final byte[] address, 
final byte addressType);
 
  356     private boolean removeDiscoveredDeviceImpl2j(
final BDAddressAndType addressAndType) {
 
  357         synchronized(discoveredDevicesLock) {
 
  358             for(
final Iterator<WeakReference<BTDevice>> it = discoveredDevices.iterator(); it.hasNext();) {
 
  372         final ArrayList<BTDevice> res = 
new ArrayList<BTDevice>();
 
  373         synchronized(discoveredDevicesLock) {
 
  374             for(
final Iterator<WeakReference<BTDevice>> it = discoveredDevices.iterator(); it.hasNext();) {
 
  385     private void cleanDiscoveredDevice() {
 
  386         synchronized(discoveredDevicesLock) {
 
  387             for(
final Iterator<WeakReference<BTDevice>> it = discoveredDevices.iterator(); it.hasNext();) {
 
  398         final boolean added = addStatusListenerImpl(
null, l);
 
  399         if( PRINT_DEVICE_LISTS || DEBUG ) {
 
  410         if( !isClosing.get() ) {
 
  411             res = removeStatusListenerImpl(l);
 
  413         if( PRINT_DEVICE_LISTS || DEBUG ) {
 
  426         printDeviceListsImpl();
 
  427         List<WeakReference<BTDevice>> _discoveredDevices;
 
  428         synchronized(discoveredDevicesLock) {
 
  430             _discoveredDevices = 
new ArrayList<WeakReference<BTDevice>>(discoveredDevices);
 
  432         final int sz = _discoveredDevices.size();
 
  433         BTUtils.
fprintf_td(System.err, 
"- BTAdapter::DiscoveredDevicesJ: %d elements%s", sz, System.lineSeparator());
 
  435         for(
final Iterator<WeakReference<BTDevice>> it = _discoveredDevices.iterator(); it.hasNext(); ++idx) {
 
  438                 BTUtils.
fprintf_td(System.err, 
"  - %d / %d: nil%s", (idx+1), sz, System.lineSeparator());
 
  445     private final native 
void printDeviceListsImpl();
 
  453             final boolean initialSetting = oldmask.
isEmpty();
 
  455                 if( initialSetting ) {
 
  456                     System.err.println(
"Adapter.StatusListener.SETTINGS: "+oldmask+
" -> "+newmask+
", initial "+changedmask+
" on "+a);
 
  458                     System.err.println(
"Adapter.StatusListener.SETTINGS: "+oldmask+
" -> "+newmask+
", changed "+changedmask+
" on "+a);
 
  461             if( initialSetting ) {
 
  462                 powered_state.set( newmask.
isSet(AdapterSettings.SettingType.POWERED) );
 
  463                 isDiscoverable.set( newmask.
isSet(AdapterSettings.SettingType.DISCOVERABLE) );
 
  466             if( changedmask.
isSet(AdapterSettings.SettingType.POWERED) ) {
 
  467                 final boolean _isPowered = newmask.
isSet(AdapterSettings.SettingType.POWERED);
 
  468                 if( powered_state.compareAndSet(!_isPowered, _isPowered) ) {
 
  474             if( changedmask.
isSet(AdapterSettings.SettingType.DISCOVERABLE) ) {
 
  475                 final boolean _isDiscoverable = newmask.
isSet(AdapterSettings.SettingType.DISCOVERABLE);
 
  476                 if( isDiscoverable.compareAndSet(!_isDiscoverable, _isDiscoverable) ) {
 
  481         public void discoveringChanged(
final BTAdapter adapter, 
final ScanType currentMeta, 
final ScanType changedType, 
final boolean changedEnabled, 
final boolean keepAlive, 
final long timestamp) {
 
  483                 System.err.println(
"Adapter.StatusListener.DISCOVERING: meta "+currentMeta+
", changed["+changedType+
", enabled "+changedEnabled+
", keepAlive "+keepAlive+
"] on "+adapter);
 
  486             currentMetaScanType.set(currentMeta);
 
  489         public boolean deviceFound(
final BTDevice device, 
final long timestamp) {
 
  490             synchronized(discoveredDevicesLock) {
 
  491                 cleanDiscoveredDevice();
 
  492                 discoveredDevices.add(
new WeakReference<BTDevice>(device));
 
  494             if( PRINT_DEVICE_LISTS || DEBUG ) {
 
  495                 System.err.println(
"Adapter.FOUND: discoveredDevices "+ discoveredDevices.size() + 
": "+device+
", on "+device.getAdapter());
 
  501         public void deviceUpdated(
final BTDevice device, 
final EIRDataTypeSet updateMask, 
final long timestamp) {
 
  502             final boolean rssiUpdated = updateMask.isSet( EIRDataTypeSet.DataType.RSSI );
 
  503             final boolean mdUpdated = updateMask.isSet( EIRDataTypeSet.DataType.MANUF_DATA );
 
  504             if( DEBUG && !rssiUpdated && !mdUpdated) {
 
  505                 System.err.println(
"Adapter.UPDATED: "+updateMask+
" of "+device+
" on "+device.getAdapter());
 
  511         public void deviceConnected(
final BTDevice device, 
final short handle, 
final long timestamp) {
 
  513                 System.err.println(
"Adapter.CONNECTED: "+device+
" on "+device.getAdapter());
 
  518         public void devicePairingState(
final BTDevice device, 
final SMPPairingState state, 
final PairingMode mode, 
final long timestamp) {
 
  520                 System.err.println(
"Adapter.PAIRING_STATE: state "+state+
", mode "+mode+
": "+device);
 
  525         public void deviceReady(
final BTDevice device, 
final long timestamp) {
 
  527                 System.err.println(
"Adapter.READY: "+device);
 
  532         public void deviceDisconnected(
final BTDevice device, 
final HCIStatusCode reason, 
final short handle, 
final long timestamp) {
 
  534                 System.err.println(
"Adapter.DISCONNECTED: Reason "+reason+
", old handle 0x"+Integer.toHexString(handle)+
": "+device+
" on "+device.getAdapter());
 
  540             return "AdapterStatusListener[adapter "+addressAndType.
toString()+
"]";
 
  576      DBTObject findInCache(
final String name, 
final String identifier, 
final BTType type) {
 
  577         final boolean anyType = BTType.NONE == type;
 
  578         final boolean deviceType = BTType.DEVICE == type;
 
  579         final boolean serviceType = BTType.GATT_SERVICE == type;
 
  580         final boolean charType = BTType.GATT_CHARACTERISTIC== type;
 
  581         final boolean descType = BTType.GATT_DESCRIPTOR == type;
 
  583         if( !anyType && !deviceType && !serviceType && !charType && !descType ) {
 
  586         synchronized(discoveredDevicesLock) {
 
  587             cleanDiscoveredDevice();
 
  589             if( 
null == name && 
null == identifier && ( anyType || deviceType ) ) {
 
  591                 if( discoveredDevices.size() > 0 ) {
 
  592                     return (DBTDevice) discoveredDevices.get(0).get();
 
  596             for(
int devIdx = discoveredDevices.size() - 1; devIdx >= 0; devIdx-- ) {
 
  597                 final DBTDevice device = (DBTDevice) discoveredDevices.get(devIdx).get();
 
  598                 if( ( anyType || deviceType ) ) {
 
  599                     if( 
null != name && 
null != identifier &&
 
  600                         device.getName().equals(name) &&
 
  601                         device.getAddressAndType().address.toString().equals(identifier)
 
  606                     if( 
null != identifier &&
 
  607                         device.getAddressAndType().address.toString().equals(identifier)
 
  613                         device.getName().equals(name)
 
  619                 if( anyType || serviceType || charType || descType ) {
 
  620                     final DBTObject dbtObj = device.findInCache(identifier, type);
 
  621                     if( 
null != dbtObj ) {
 
  630      DBTDevice findDeviceInCache(
final String name, 
final BDAddressAndType addressAndType) {
 
  631         synchronized(discoveredDevicesLock) {
 
  632             cleanDiscoveredDevice();
 
  634             if( 
null == name && 
null == addressAndType ) {
 
  636                 if( discoveredDevices.size() > 0 ) {
 
  637                     return (DBTDevice) discoveredDevices.get(0).get();
 
  641             for(
int devIdx = discoveredDevices.size() - 1; devIdx >= 0; devIdx-- ) {
 
  642                 final DBTDevice device = (DBTDevice) discoveredDevices.get(devIdx).get();
 
  643                 if( 
null != name && 
null != addressAndType &&
 
  644                     device.getName().equals(name) &&
 
  645                     device.getAddressAndType().equals(addressAndType)
 
  650                 if( 
null != addressAndType &&
 
  651                     device.getAddressAndType().equals(addressAndType)
 
  657                     device.getName().equals(name)