26 package jau.direct_bt;
28 import java.security.AccessController;
29 import java.security.PrivilegedAction;
30 import java.util.ArrayList;
31 import java.util.Iterator;
32 import java.util.List;
33 import java.util.concurrent.CopyOnWriteArrayList;
34 import java.util.function.Consumer;
35 import java.util.function.Predicate;
55 private static volatile boolean isJVMShuttingDown =
false;
56 private static final List<Runnable> userShutdownHooks =
new ArrayList<Runnable>();
57 private static boolean unifyUUID128Bit =
true;
60 AccessController.doPrivileged(
new PrivilegedAction<Object>() {
63 Runtime.getRuntime().addShutdownHook(
64 new Thread(
null,
new Runnable() {
68 } },
"DBTManager_ShutdownHook" ) ) ;
73 private static synchronized void shutdownImpl(
final boolean _isJVMShuttingDown) {
74 isJVMShuttingDown = _isJVMShuttingDown;
76 System.err.println(
"DBTManager.shutdown() START: JVM Shutdown "+isJVMShuttingDown+
", on thread "+Thread.currentThread().getName());
78 synchronized(userShutdownHooks) {
79 final int cshCount = userShutdownHooks.size();
80 for(
int i=0; i < cshCount; i++) {
83 System.err.println(
"DBTManager.shutdown - userShutdownHook #"+(i+1)+
"/"+cshCount);
85 userShutdownHooks.get(i).run();
86 }
catch(
final Throwable t) {
87 System.err.println(
"DBTManager.shutdown: Caught "+t.getClass().getName()+
" during userShutdownHook #"+(i+1)+
"/"+cshCount);
93 userShutdownHooks.clear();
96 System.err.println(
"DBTManager.shutdown(): Post userShutdownHook");
102 }
catch(
final Throwable t) {
103 System.err.println(
"DBTManager.shutdown: Caught "+t.getClass().getName()+
" during DBTManager.shutdown()");
110 System.err.println(Thread.currentThread().getName()+
" - DBTManager.shutdown() END JVM Shutdown "+isJVMShuttingDown);
124 synchronized( userShutdownHooks ) {
125 if( !userShutdownHooks.contains( runnable ) ) {
127 userShutdownHooks.add(0, runnable);
129 userShutdownHooks.add( runnable );
155 private long nativeInstance;
156 private final List<BTAdapter> adapters =
new CopyOnWriteArrayList<BTAdapter>();
157 private final List<ChangedAdapterSetListener> changedAdapterSetListenerList =
new CopyOnWriteArrayList<ChangedAdapterSetListener>();
159 private final Settings settings;
168 return findInCache((
DBTObject)parent, type, name, identifier);
173 return find(type, name, identifier, parent, 0);
177 public List<BTAdapter>
getAdapters() {
return new ArrayList<BTAdapter>(adapters); }
181 for(
final Iterator<BTAdapter> iter = adapters.iterator(); iter.hasNext(); ) {
209 final List<BTGattService> res =
new ArrayList<BTGattService>();
210 for(
final Iterator<BTAdapter> iterA=adapters.iterator(); iterA.hasNext(); ) {
213 for(
final Iterator<BTDevice> iterD=devices.iterator(); iterD.hasNext(); ) {
214 final BTDevice device = iterD.next();
215 final List<BTGattService> devServices = device.
getServices();
216 if(
null != devServices ) {
217 res.addAll(devServices);
231 for(
final Iterator<BTAdapter> iter = adapters.iterator(); iter.hasNext(); ) {
255 changedAdapterSetListenerList.add(l);
257 adapters.forEach(
new Consumer<BTAdapter>() {
259 public void accept(
final BTAdapter adapter) {
268 final int count[] = { 0 };
269 changedAdapterSetListenerList.removeIf(
new Predicate<ChangedAdapterSetListener>() {
282 private native List<BTAdapter> getAdapterListImpl();
283 private native
BTAdapter getAdapterImpl(
int dev_id);
290 final boolean removeAdapter(
final DBTAdapter adapter) {
291 if( adapters.remove(adapter) ) {
293 System.err.println(
"DBTManager.removeAdapter: Removed "+adapter);
298 System.err.println(
"DBTManager.removeAdapter: Not found "+adapter);
305 final void removeAdapterCB(
final int dev_id,
final int opc_reason) {
306 final BTAdapter[] removed = {
null };
307 final int count[] = { 0 };
308 adapters.removeIf(
new Predicate<BTAdapter>() {
310 public boolean test(
final BTAdapter a) {
311 if( 0 == count[0] && dev_id == a.getDevID() ) {
320 if(
null != removed[0] ) {
322 System.err.println(
"DBTManager.removeAdapterCB[dev_id "+dev_id+
", opc 0x"+Integer.toHexString(opc_reason)+
323 "]: removing "+removed[0].toString());
325 if( 0x0005 == opc_reason ) {
327 changedAdapterSetListenerList.forEach(
new Consumer<ChangedAdapterSetListener>() {
329 public void accept(
final ChangedAdapterSetListener t) {
330 t.adapterRemoved( removed[0] );
336 System.err.println(
"DBTManager.removeAdapterCB[dev_id "+dev_id+
", opc 0x"+Integer.toHexString(opc_reason)+
337 "]: removed "+count[0]+
" adapter, size "+adapters.size());
341 private final void updatedAdapterCB(
final int dev_id,
final int opc_reason) {
342 final BTAdapter preInstance =
getAdapter(dev_id);
343 if(
null != preInstance ) {
345 System.err.println(
"DBTManager.updatedAdapterCB[dev_id "+dev_id+
", opc 0x"+Integer.toHexString(opc_reason)+
346 "]: existing "+preInstance.toString()+
", size "+adapters.size());
350 final BTAdapter newInstance = getAdapterImpl(dev_id);
351 if(
null == newInstance ) {
353 System.err.println(
"DBTManager.updatedAdapterCB[dev_id "+dev_id+
", opc 0x"+Integer.toHexString(opc_reason)+
354 "]: Adapter not found, size "+adapters.size());
358 final boolean added = adapters.add(newInstance);
360 System.err.println(
"DBTManager.updatedAdapterCB[dev_id "+dev_id+
", opc 0x"+Integer.toHexString(opc_reason)+
361 "]: added "+added+
": new "+newInstance.toString()+
", size "+adapters.size());
363 if( added && 0x0004 == opc_reason ) {
365 changedAdapterSetListenerList.forEach(
new Consumer<ChangedAdapterSetListener>() {
367 public void accept(
final ChangedAdapterSetListener t) {
368 t.adapterAdded(newInstance);
373 private native
void initImpl(
final boolean unifyUUID128Bit,
final int btMode)
throws BTException;
374 private native
void deleteImpl(
long nativeInstance);
377 initImpl(unifyUUID128Bit, BTFactory.DEFAULT_BTMODE.value);
379 adapters.addAll(getAdapterListImpl());
380 }
catch (
final BTException be) {
381 be.printStackTrace();
383 settings =
new Settings() {
385 public final boolean isDirectBT() {
389 public String toString() {
390 return "Settings[dbt true]";
399 return LazySingletonHolder.singleton;
402 private static class LazySingletonHolder {
413 for(
final Iterator<BTAdapter> ia= adapters.iterator(); ia.hasNext(); ) {
418 deleteImpl(nativeInstance);
454 DBTObject findInCache(
final String name,
final String identifier,
final BTType type) {
458 if(
null == name &&
null == identifier && ( anyType || adapterType ) ) {
460 if( adapters.size() > 0 ) {
465 for(
final Iterator<BTAdapter> iter = adapters.iterator(); iter.hasNext(); ) {
466 final DBTAdapter adapter = (DBTAdapter) iter.next();
467 if( !adapter.isValid() ) {
470 if( ( anyType || adapterType ) ) {
471 if(
null != name &&
null != identifier &&
472 adapter.getName().equals(name) &&
473 adapter.getAddressAndType().address.toString().equals(identifier)
478 if(
null != identifier &&
479 adapter.getAddressAndType().address.toString().equals(identifier)
485 adapter.getName().equals(name)
491 final DBTObject dbtObj = adapter.findInCache(name, identifier, type);
492 if(
null != dbtObj ) {
499 DBTObject findInCache(
final DBTObject parent,
final BTType type,
final String name,
final String identifier) {
500 if(
null == parent ) {
501 return findInCache(name, identifier, type);
503 final boolean anyType = BTType.NONE == type;
504 final boolean deviceType = BTType.DEVICE == type;
505 final boolean serviceType = BTType.GATT_SERVICE == type;
506 final boolean charType = BTType.GATT_CHARACTERISTIC== type;
507 final boolean descType = BTType.GATT_DESCRIPTOR == type;
509 final BTType parentType = parent.getBluetoothType();
511 if( BTType.ADAPTER == parentType &&
512 ( anyType || deviceType || serviceType || charType || descType )
515 return ((DBTAdapter) parent).findInCache(name, identifier, type);
517 if( BTType.DEVICE == parentType &&
518 ( anyType || serviceType || charType || descType )
521 return ((DBTDevice) parent).findInCache(identifier, type);
523 if( BTType.GATT_SERVICE == parentType &&
524 ( anyType || charType || descType )
527 final DBTGattService service = (DBTGattService) parent;
528 if( !service.checkServiceCache() ) {
531 return service.findInCache(identifier, type);
533 if( BTType.GATT_CHARACTERISTIC == parentType &&
534 ( anyType || descType )
537 final DBTGattChar characteristic = (DBTGattChar) parent;
538 if( !characteristic.checkServiceCache() ) {
541 return characteristic.findInCache(identifier, type);