View Javadoc

1   /**
2    * BlueCove BlueZ module - Java library for Bluetooth on Linux
3    *  Copyright (C) 2008 Mina Shokry
4    *  Copyright (C) 2007-2008 Vlad Skarzhevskyy
5    *
6    * This program is free software: you can redistribute it and/or modify
7    * it under the terms of the GNU General Public License as published by
8    * the Free Software Foundation, either version 3 of the License, or
9    * (at your option) any later version.
10   *
11   * This program is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU General Public License for more details.
15   *
16   *  You should have received a copy of the GNU General Public License
17   *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18   *
19   * @version $Id: BluetoothStackBlueZ.java 2557 2008-12-11 08:19:30Z skarzhevskyy $
20   */
21  package com.intel.bluetooth;
22  
23  import java.io.IOException;
24  import java.util.Hashtable;
25  import java.util.Vector;
26  
27  import javax.bluetooth.BluetoothStateException;
28  import javax.bluetooth.DataElement;
29  import javax.bluetooth.DeviceClass;
30  import javax.bluetooth.DiscoveryListener;
31  import javax.bluetooth.RemoteDevice;
32  import javax.bluetooth.ServiceRecord;
33  import javax.bluetooth.ServiceRegistrationException;
34  import javax.bluetooth.UUID;
35  
36  /**
37   * Property "bluecove.deviceID" or "bluecove.deviceAddress" can be used to
38   * select Local Bluetooth device.
39   * 
40   */
41  class BluetoothStackBlueZ implements BluetoothStack {
42  
43      public static final String NATIVE_BLUECOVE_LIB_BLUEZ = "bluecove";
44  
45      static final int NATIVE_LIBRARY_VERSION = BlueCoveImpl.nativeLibraryVersionExpected;
46  
47      // TODO what is the real number for Attributes retrievable ?
48      private final static int ATTR_RETRIEVABLE_MAX = 256;
49  
50      private final static int LISTEN_BACKLOG_RFCOMM = 4;
51  
52      private final static int LISTEN_BACKLOG_L2CAP = 4;
53  
54      private final static Vector devicesUsed = new Vector();
55  
56      private int deviceID = -1;
57  
58      private int deviceDescriptor;
59  
60      private long localDeviceBTAddress;
61  
62      private long sdpSesion;
63  
64      private int registeredServicesCount = 0;
65  
66      private Hashtable/* <String,String> */propertiesMap;
67  
68      private DiscoveryListener discoveryListener;
69  
70      // Prevent the device from been discovered twice
71      private Vector/* <RemoteDevice> */discoveredDevices;
72  
73      private boolean deviceInquiryCanceled = false;
74  
75      private final int l2cap_receiveMTU_max = 65535;
76  
77      BluetoothStackBlueZ() {
78      }
79  
80      // --- Library initialization
81  
82      public String getStackID() {
83          return BlueCoveImpl.STACK_BLUEZ;
84      }
85  
86      public String toString() {
87          if (deviceID >= 0) {
88              return getStackID() + ":" + deviceID;
89          } else {
90              return getStackID();
91          }
92      }
93  
94      /*
95       * (non-Javadoc)
96       * 
97       * @see com.intel.bluetooth.BluetoothStack#isNativeCodeLoaded()
98       */
99      public native boolean isNativeCodeLoaded();
100 
101     /*
102      * (non-Javadoc)
103      * 
104      * @see com.intel.bluetooth.BluetoothStack#requireNativeLibraries()
105      */
106     public LibraryInformation[] requireNativeLibraries() {
107         return LibraryInformation.library(NATIVE_BLUECOVE_LIB_BLUEZ);
108     }
109 
110     public native int getLibraryVersionNative();
111 
112     public int getLibraryVersion() throws BluetoothStateException {
113         int version = getLibraryVersionNative();
114         if (version != NATIVE_LIBRARY_VERSION) {
115             DebugLog.fatal("BlueCove native library version mismatch " + version + " expected " + NATIVE_LIBRARY_VERSION);
116             throw new BluetoothStateException("BlueCove native library version mismatch");
117         }
118         return version;
119     }
120 
121     public int detectBluetoothStack() {
122         return BlueCoveImpl.BLUECOVE_STACK_DETECT_BLUEZ;
123     }
124 
125     private native int nativeGetDeviceID(int id, long findLocalDeviceBTAddress) throws BluetoothStateException;
126 
127     private native int nativeOpenDevice(int deviceID) throws BluetoothStateException;
128 
129     public void initialize() throws BluetoothStateException {
130         long findLocalDeviceBTAddress = -1;
131         int findID = BlueCoveImpl.getConfigProperty(BlueCoveConfigProperties.PROPERTY_LOCAL_DEVICE_ID, -1);
132         String deviceAddressStr = BlueCoveImpl.getConfigProperty(BlueCoveConfigProperties.PROPERTY_LOCAL_DEVICE_ADDRESS);
133         if (deviceAddressStr != null) {
134             findLocalDeviceBTAddress = Long.parseLong(deviceAddressStr, 16);
135         }
136         int foundDeviceID = nativeGetDeviceID(findID, findLocalDeviceBTAddress);
137         if (devicesUsed.contains(new Long(foundDeviceID))) {
138             throw new BluetoothStateException("LocalDevice " + foundDeviceID + " alredy in use");
139         }
140 
141         this.deviceID = foundDeviceID;
142         DebugLog.debug("localDeviceID", deviceID);
143         deviceDescriptor = nativeOpenDevice(deviceID);
144         localDeviceBTAddress = getLocalDeviceBluetoothAddressImpl(deviceDescriptor);
145         propertiesMap = new Hashtable/* <String,String> */();
146         final String TRUE = "true";
147         final String FALSE = "false";
148         propertiesMap.put(BluetoothConsts.PROPERTY_BLUETOOTH_CONNECTED_DEVICES_MAX, "7");
149         propertiesMap.put(BluetoothConsts.PROPERTY_BLUETOOTH_SD_TRANS_MAX, "7");
150         propertiesMap.put(BluetoothConsts.PROPERTY_BLUETOOTH_CONNECTED_INQUIRY_SCAN, TRUE);
151         propertiesMap.put(BluetoothConsts.PROPERTY_BLUETOOTH_CONNECTED_PAGE_SCAN, TRUE);
152         propertiesMap.put(BluetoothConsts.PROPERTY_BLUETOOTH_CONNECTED_INQUIRY, TRUE);
153         propertiesMap.put(BluetoothConsts.PROPERTY_BLUETOOTH_CONNECTED_PAGE, TRUE);
154         propertiesMap.put(BluetoothConsts.PROPERTY_BLUETOOTH_SD_ATTR_RETRIEVABLE_MAX, String.valueOf(ATTR_RETRIEVABLE_MAX));
155         propertiesMap.put(BluetoothConsts.PROPERTY_BLUETOOTH_MASTER_SWITCH, FALSE);
156         propertiesMap.put(BluetoothConsts.PROPERTY_BLUETOOTH_L2CAP_RECEIVEMTU_MAX, String.valueOf(l2cap_receiveMTU_max));
157         // propertiesMap.put("bluecove.radio.version", );
158         // propertiesMap.put("bluecove.radio.manufacturer", );
159         // propertiesMap.put("bluecove.stack.version", );
160         propertiesMap.put(BlueCoveLocalDeviceProperties.LOCAL_DEVICE_PROPERTY_DEVICE_ID, String.valueOf(deviceID));
161 
162         devicesUsed.addElement(new Long(deviceID));
163     }
164 
165     private native void nativeCloseDevice(int deviceDescriptor);
166 
167     public void destroy() {
168         if (sdpSesion != 0) {
169             try {
170                 long s = sdpSesion;
171                 sdpSesion = 0;
172                 closeSDPSessionImpl(s, true);
173             } catch (ServiceRegistrationException ignore) {
174             }
175         }
176         nativeCloseDevice(deviceDescriptor);
177         if (deviceID >= 0) {
178             devicesUsed.removeElement(new Long(deviceID));
179             deviceID = -1;
180         }
181     }
182 
183     public native void enableNativeDebug(Class nativeDebugCallback, boolean on);
184 
185     /*
186      * (non-Javadoc)
187      * 
188      * @see
189      * com.intel.bluetooth.BluetoothStack#isCurrentThreadInterruptedCallback()
190      */
191     public boolean isCurrentThreadInterruptedCallback() {
192         return UtilsJavaSE.isCurrentThreadInterrupted();
193     }
194 
195     /*
196      * (non-Javadoc)
197      * 
198      * @see com.intel.bluetooth.BluetoothStack#getFeatureSet()
199      */
200     public int getFeatureSet() {
201         return FEATURE_SERVICE_ATTRIBUTES | FEATURE_L2CAP;
202     }
203 
204     private native int[] getLocalDevicesID();
205 
206     // --- LocalDevice
207 
208     private native long getLocalDeviceBluetoothAddressImpl(int deviceDescriptor) throws BluetoothStateException;
209 
210     public String getLocalDeviceBluetoothAddress() throws BluetoothStateException {
211         return RemoteDeviceHelper.getBluetoothAddress(getLocalDeviceBluetoothAddressImpl(deviceDescriptor));
212     }
213 
214     private native int nativeGetDeviceClass(int deviceDescriptor);
215 
216     public DeviceClass getLocalDeviceClass() {
217         int record = nativeGetDeviceClass(deviceDescriptor);
218         if (record == 0xff000000) {
219             // could not be determined
220             return null;
221         }
222         return new DeviceClass(record);
223     }
224 
225     private native String nativeGetDeviceName(int deviceDescriptor);
226 
227     public String getLocalDeviceName() {
228         return nativeGetDeviceName(deviceDescriptor);
229     }
230 
231     public boolean isLocalDevicePowerOn() {
232         // Have no idea how turn on and off device on BlueZ, as well to how to
233         // detect this condition.
234         return true;
235     }
236 
237     public String getLocalDeviceProperty(String property) {
238         if (BlueCoveLocalDeviceProperties.LOCAL_DEVICE_DEVICES_LIST.equals(property)) {
239             int[] ids = getLocalDevicesID();
240             StringBuffer b = new StringBuffer();
241             if (ids != null) {
242                 for (int i = 0; i < ids.length; i++) {
243                     if (i != 0) {
244                         b.append(',');
245                     }
246                     b.append(String.valueOf(ids[i]));
247                 }
248             }
249             return b.toString();
250         }
251         // Some Hack and testing functions, not documented
252         if (property.startsWith("bluecove.nativeFunction:")) {
253             String functionDescr = property.substring(property.indexOf(':') + 1, property.length());
254             int paramIdx = functionDescr.indexOf(':');
255             if (paramIdx == -1) {
256                 throw new RuntimeException("Invalid native function " + functionDescr + "; arguments expected");
257             }
258             String function = functionDescr.substring(0, paramIdx);
259             long address = RemoteDeviceHelper.getAddress(functionDescr.substring(function.length() + 1, functionDescr.length()));
260             if ("getRemoteDeviceVersionInfo".equals(function)) {
261                 return getRemoteDeviceVersionInfo(address);
262             } else if ("getRemoteDeviceRSSI".equals(function)) {
263                 return String.valueOf(getRemoteDeviceRSSI(address));
264             }
265             return null;
266         }
267         return (String) propertiesMap.get(property);
268     }
269 
270     private native int nativeGetLocalDeviceDiscoverable(int deviceDescriptor);
271 
272     public int getLocalDeviceDiscoverable() {
273         return nativeGetLocalDeviceDiscoverable(deviceDescriptor);
274     }
275 
276     private native int nativeSetLocalDeviceDiscoverable(int deviceDescriptor, int mode);
277 
278     /**
279      * From JSR-82 docs
280      * 
281      * @return <code>true</code> if the request succeeded, otherwise
282      *         <code>false</code> if the request failed because the BCC denied
283      *         the request; <code>false</code> if the Bluetooth system does not
284      *         support the access mode specified in <code>mode</code>
285      */
286     public boolean setLocalDeviceDiscoverable(int mode) throws BluetoothStateException {
287         int curentMode = getLocalDeviceDiscoverable();
288         if (curentMode == mode) {
289             return true;
290         } else {
291             int error = nativeSetLocalDeviceDiscoverable(deviceDescriptor, mode);
292             if (error != 0) {
293                 DebugLog.error("Unable to change discovery mode. It may be because you aren't root; " + error);
294                 return false;
295             }
296             return true;
297         }
298     }
299 
300     /*
301      * (non-Javadoc)
302      * 
303      * @see com.intel.bluetooth.BluetoothStack#setLocalDeviceServiceClasses(int)
304      */
305     public void setLocalDeviceServiceClasses(int classOfDevice) {
306         throw new NotSupportedRuntimeException(getStackID());
307     }
308 
309     // --- Remote Device authentication
310 
311     public boolean authenticateRemoteDevice(long address) throws IOException {
312         return false;
313     }
314 
315     /*
316      * (non-Javadoc)
317      * 
318      * @see com.intel.bluetooth.BluetoothStack#authenticateRemoteDevice(long,
319      * java.lang.String)
320      */
321     public boolean authenticateRemoteDevice(long address, String passkey) throws IOException {
322         return false;
323     }
324 
325     /*
326      * (non-Javadoc)
327      * 
328      * @see
329      * com.intel.bluetooth.BluetoothStack#removeAuthenticationWithRemoteDevice
330      * (long)
331      */
332     public void removeAuthenticationWithRemoteDevice(long address) throws IOException {
333         // TODO
334         throw new NotSupportedIOException(getStackID());
335     }
336 
337     // --- Some testing functions accessible by LocalDevice.getProperty
338 
339     private native String getRemoteDeviceVersionInfoImpl(int deviceDescriptor, long address);
340 
341     public String getRemoteDeviceVersionInfo(long address) {
342         return getRemoteDeviceVersionInfoImpl(this.deviceDescriptor, address);
343     }
344 
345     private native int getRemoteDeviceRSSIImpl(int deviceDescriptor, long address);
346 
347     public int getRemoteDeviceRSSI(long address) {
348         return getRemoteDeviceRSSIImpl(this.deviceDescriptor, address);
349     }
350 
351     public RemoteDevice[] retrieveDevices(int option) {
352         return null;
353     }
354 
355     public Boolean isRemoteDeviceTrusted(long address) {
356         return null;
357     }
358 
359     public Boolean isRemoteDeviceAuthenticated(long address) {
360         return null;
361     }
362 
363     // --- Device Inquiry
364 
365     private native int runDeviceInquiryImpl(DeviceInquiryRunnable inquiryRunnable, DeviceInquiryThread startedNotify, int deviceID, int deviceDescriptor, int accessCode, int inquiryLength,
366             int maxResponses, DiscoveryListener listener) throws BluetoothStateException;
367 
368     public boolean startInquiry(int accessCode, DiscoveryListener listener) throws BluetoothStateException {
369         if (discoveryListener != null) {
370             throw new BluetoothStateException("Another inquiry already running");
371         }
372         discoveryListener = listener;
373         discoveredDevices = new Vector();
374         deviceInquiryCanceled = false;
375         DeviceInquiryRunnable inquiryRunnable = new DeviceInquiryRunnable() {
376 
377             public int runDeviceInquiry(DeviceInquiryThread startedNotify, int accessCode, DiscoveryListener listener) throws BluetoothStateException {
378                 try {
379                     int discType = runDeviceInquiryImpl(this, startedNotify, deviceID, deviceDescriptor, accessCode, 8, 20, listener);
380                     if (deviceInquiryCanceled) {
381                         return DiscoveryListener.INQUIRY_TERMINATED;
382                     }
383                     return discType;
384                 } finally {
385                     discoveryListener = null;
386                     discoveredDevices = null;
387                 }
388             }
389 
390             public void deviceDiscoveredCallback(DiscoveryListener listener, long deviceAddr, int deviceClass, String deviceName, boolean paired) {
391                 RemoteDevice remoteDevice = RemoteDeviceHelper.createRemoteDevice(BluetoothStackBlueZ.this, deviceAddr, deviceName, paired);
392                 if (deviceInquiryCanceled || (discoveryListener == null) || (discoveredDevices == null) || (discoveredDevices.contains(remoteDevice))) {
393                     return;
394                 }
395                 discoveredDevices.addElement(remoteDevice);
396                 DeviceClass cod = new DeviceClass(deviceClass);
397                 DebugLog.debug("deviceDiscoveredCallback address", remoteDevice.getBluetoothAddress());
398                 DebugLog.debug("deviceDiscoveredCallback deviceClass", cod);
399                 listener.deviceDiscovered(remoteDevice, cod);
400 
401             }
402         };
403         return DeviceInquiryThread.startInquiry(this, inquiryRunnable, accessCode, listener);
404     }
405 
406     private native boolean deviceInquiryCancelImpl(int deviceDescriptor);
407 
408     public boolean cancelInquiry(DiscoveryListener listener) {
409         if (discoveryListener != null && discoveryListener == listener) {
410             deviceInquiryCanceled = true;
411             return deviceInquiryCancelImpl(deviceDescriptor);
412         }
413         return false;
414     }
415 
416     private native String getRemoteDeviceFriendlyNameImpl(int deviceDescriptor, long remoteAddress) throws IOException;
417 
418     public String getRemoteDeviceFriendlyName(long address) throws IOException {
419         return getRemoteDeviceFriendlyNameImpl(deviceDescriptor, address);
420     }
421 
422     // --- Service search
423 
424     private native int runSearchServicesImpl(SearchServicesThread sst, long localDeviceBTAddress, byte[][] uuidValues, long remoteDeviceAddress)
425             throws SearchServicesException;
426 
427     public int searchServices(int[] attrSet, UUID[] uuidSet, RemoteDevice device, DiscoveryListener listener) throws BluetoothStateException {
428 
429         SearchServicesRunnable searchRunnable = new SearchServicesRunnable() {
430 
431             public int runSearchServices(SearchServicesThread sst, int[] attrSet, UUID[] uuidSet, RemoteDevice device, DiscoveryListener listener)
432                     throws BluetoothStateException {
433                 sst.searchServicesStartedCallback();
434                 try {
435                     byte[][] uuidValues = new byte[uuidSet.length][];
436                     for (int i = 0; i < uuidSet.length; i++) {
437                         uuidValues[i] = Utils.UUIDToByteArray(uuidSet[i]);
438                     }
439                     int respCode = runSearchServicesImpl(sst, localDeviceBTAddress, uuidValues, RemoteDeviceHelper.getAddress(device));
440                     if ((respCode != DiscoveryListener.SERVICE_SEARCH_ERROR) && (sst.isTerminated())) {
441                         return DiscoveryListener.SERVICE_SEARCH_TERMINATED;
442                     } else if (respCode == DiscoveryListener.SERVICE_SEARCH_COMPLETED) {
443                         Vector records = sst.getServicesRecords();
444                         if (records.size() != 0) {
445                             DebugLog.debug("SearchServices finished", sst.getTransID());
446                             ServiceRecord[] servRecordArray = (ServiceRecord[]) Utils.vector2toArray(records, new ServiceRecord[records.size()]);
447                             listener.servicesDiscovered(sst.getTransID(), servRecordArray);
448                         }
449                         if (records.size() != 0) {
450                             return DiscoveryListener.SERVICE_SEARCH_COMPLETED;
451                         } else {
452                             return DiscoveryListener.SERVICE_SEARCH_NO_RECORDS;
453                         }
454                     } else {
455                         return respCode;
456                     }
457                 } catch (SearchServicesDeviceNotReachableException e) {
458                     return DiscoveryListener.SERVICE_SEARCH_DEVICE_NOT_REACHABLE;
459                 } catch (SearchServicesTerminatedException e) {
460                     return DiscoveryListener.SERVICE_SEARCH_TERMINATED;
461                 } catch (SearchServicesException e) {
462                     return DiscoveryListener.SERVICE_SEARCH_ERROR;
463                 }
464             }
465         };
466         return SearchServicesThread.startSearchServices(this, searchRunnable, attrSet, uuidSet, device, listener);
467     }
468 
469     public boolean serviceDiscoveredCallback(SearchServicesThread sst, long sdpSession, long handle) {
470         if (sst.isTerminated()) {
471             return true;
472         }
473         ServiceRecordImpl servRecord = new ServiceRecordImpl(this, sst.getDevice(), handle);
474         int[] attrIDs = sst.getAttrSet();
475         long remoteDeviceAddress = RemoteDeviceHelper.getAddress(sst.getDevice());
476         populateServiceRecordAttributeValuesImpl(this.localDeviceBTAddress, remoteDeviceAddress, sdpSession, handle, attrIDs, servRecord);
477         sst.addServicesRecords(servRecord);
478         return false;
479     }
480 
481     public boolean cancelServiceSearch(int transID) {
482         SearchServicesThread sst = SearchServicesThread.getServiceSearchThread(transID);
483         if (sst != null) {
484             return sst.setTerminated();
485         } else {
486             return false;
487         }
488     }
489 
490     private native boolean populateServiceRecordAttributeValuesImpl(long localDeviceBTAddress, long remoteDeviceAddress, long sdpSession, long handle,
491             int[] attrIDs, ServiceRecordImpl serviceRecord);
492 
493     public boolean populateServicesRecordAttributeValues(ServiceRecordImpl serviceRecord, int[] attrIDs) throws IOException {
494         long remoteDeviceAddress = RemoteDeviceHelper.getAddress(serviceRecord.getHostDevice());
495         return populateServiceRecordAttributeValuesImpl(this.localDeviceBTAddress, remoteDeviceAddress, 0, serviceRecord.getHandle(), attrIDs, serviceRecord);
496     }
497 
498     // --- SDP Server
499 
500     private native long openSDPSessionImpl() throws ServiceRegistrationException;
501 
502     private synchronized long getSDPSession() throws ServiceRegistrationException {
503         if (this.sdpSesion == 0) {
504             sdpSesion = openSDPSessionImpl();
505             DebugLog.debug("created SDPSession", sdpSesion);
506         }
507         return sdpSesion;
508     }
509 
510     private native void closeSDPSessionImpl(long sdpSesion, boolean quietly) throws ServiceRegistrationException;
511 
512     private native long registerSDPServiceImpl(long sdpSesion, long localDeviceBTAddress, byte[] record) throws ServiceRegistrationException;
513 
514     private native void updateSDPServiceImpl(long sdpSesion, long localDeviceBTAddress, long handle, byte[] record) throws ServiceRegistrationException;
515 
516     private native void unregisterSDPServiceImpl(long sdpSesion, long localDeviceBTAddress, long handle, byte[] record) throws ServiceRegistrationException;
517 
518     private byte[] getSDPBinary(ServiceRecordImpl serviceRecord) throws ServiceRegistrationException {
519         byte[] blob;
520         try {
521             blob = serviceRecord.toByteArray();
522         } catch (IOException e) {
523             throw new ServiceRegistrationException(e.toString());
524         }
525         return blob;
526     }
527 
528     private synchronized void registerSDPRecord(ServiceRecordImpl serviceRecord) throws ServiceRegistrationException {
529         long handle = registerSDPServiceImpl(getSDPSession(), this.localDeviceBTAddress, getSDPBinary(serviceRecord));
530         serviceRecord.setHandle(handle);
531         serviceRecord.populateAttributeValue(BluetoothConsts.ServiceRecordHandle, new DataElement(DataElement.U_INT_4, handle));
532         registeredServicesCount++;
533     }
534 
535     private void updateSDPRecord(ServiceRecordImpl serviceRecord) throws ServiceRegistrationException {
536         updateSDPServiceImpl(getSDPSession(), this.localDeviceBTAddress, serviceRecord.getHandle(), getSDPBinary(serviceRecord));
537     }
538 
539     private synchronized void unregisterSDPRecord(ServiceRecordImpl serviceRecord) throws ServiceRegistrationException {
540         try {
541             unregisterSDPServiceImpl(getSDPSession(), this.localDeviceBTAddress, serviceRecord.getHandle(), getSDPBinary(serviceRecord));
542         } finally {
543             registeredServicesCount--;
544             if (registeredServicesCount <= 0) {
545                 registeredServicesCount = 0;
546                 DebugLog.debug("closeSDPSession", sdpSesion);
547                 long s = sdpSesion;
548                 sdpSesion = 0;
549                 closeSDPSessionImpl(s, false);
550             }
551         }
552     }
553 
554     // --- Client RFCOMM connections
555 
556     private native long connectionRfOpenClientConnectionImpl(long localDeviceBTAddress, long address, int channel, boolean authenticate, boolean encrypt,
557             int timeout) throws IOException;
558 
559     public long connectionRfOpenClientConnection(BluetoothConnectionParams params) throws IOException {
560         return connectionRfOpenClientConnectionImpl(localDeviceBTAddress, params.address, params.channel, params.authenticate, params.encrypt, params.timeout);
561     }
562 
563     public native void connectionRfCloseClientConnection(long handle) throws IOException;
564 
565     public native int rfGetSecurityOptImpl(long handle) throws IOException;
566 
567     public int rfGetSecurityOpt(long handle, int expected) throws IOException {
568         return rfGetSecurityOptImpl(handle);
569     }
570 
571     /*
572      * (non-Javadoc)
573      * 
574      * @see com.intel.bluetooth.BluetoothStack#l2Encrypt(long,long,boolean)
575      */
576     public boolean rfEncrypt(long address, long handle, boolean on) throws IOException {
577         return false;
578     }
579 
580     private native long rfServerOpenImpl(long localDeviceBTAddress, boolean authorize, boolean authenticate, boolean encrypt, boolean master, boolean timeouts,
581             int backlog) throws IOException;
582 
583     private native int rfServerGetChannelIDImpl(long handle) throws IOException;
584 
585     public long rfServerOpen(BluetoothConnectionNotifierParams params, ServiceRecordImpl serviceRecord) throws IOException {
586         long socket = rfServerOpenImpl(this.localDeviceBTAddress, params.authorize, params.authenticate, params.encrypt, params.master, params.timeouts,
587                 LISTEN_BACKLOG_RFCOMM);
588         boolean success = false;
589         try {
590             int channel = rfServerGetChannelIDImpl(socket);
591             serviceRecord.populateRFCOMMAttributes(0, channel, params.uuid, params.name, params.obex);
592             registerSDPRecord(serviceRecord);
593             success = true;
594             return socket;
595         } finally {
596             if (!success) {
597                 rfServerCloseImpl(socket, true);
598             }
599         }
600     }
601 
602     private native void rfServerCloseImpl(long handle, boolean quietly) throws IOException;
603 
604     public void rfServerClose(long handle, ServiceRecordImpl serviceRecord) throws IOException {
605         try {
606             unregisterSDPRecord(serviceRecord);
607         } finally {
608             rfServerCloseImpl(handle, false);
609         }
610     }
611 
612     public void rfServerUpdateServiceRecord(long handle, ServiceRecordImpl serviceRecord, boolean acceptAndOpen) throws ServiceRegistrationException {
613         updateSDPRecord(serviceRecord);
614     }
615 
616     public native long rfServerAcceptAndOpenRfServerConnection(long handle) throws IOException;
617 
618     public void connectionRfCloseServerConnection(long clientHandle) throws IOException {
619         connectionRfCloseClientConnection(clientHandle);
620     }
621 
622     // --- Shared Client and Server RFCOMM connections
623 
624     public int connectionRfRead(long handle) throws IOException {
625         byte[] data = new byte[1];
626         int size = connectionRfRead(handle, data, 0, 1);
627         if (size == -1) {
628             return -1;
629         }
630         return 0xFF & data[0];
631     }
632 
633     public native int connectionRfRead(long handle, byte[] b, int off, int len) throws IOException;
634 
635     public native int connectionRfReadAvailable(long handle) throws IOException;
636 
637     public native void connectionRfWrite(long handle, int b) throws IOException;
638 
639     public native void connectionRfWrite(long handle, byte[] b, int off, int len) throws IOException;
640 
641     public native void connectionRfFlush(long handle) throws IOException;
642 
643     public native long getConnectionRfRemoteAddress(long handle) throws IOException;
644 
645     // --- Client and Server L2CAP connections
646 
647     private void validateMTU(int receiveMTU, int transmitMTU) {
648         if (receiveMTU > l2cap_receiveMTU_max) {
649             throw new IllegalArgumentException("invalid ReceiveMTU value " + receiveMTU);
650         }
651     }
652 
653     private native long l2OpenClientConnectionImpl(long localDeviceBTAddress, long address, int channel, boolean authenticate, boolean encrypt, int receiveMTU,
654             int transmitMTU, int timeout) throws IOException;
655 
656     /*
657      * (non-Javadoc)
658      * 
659      * @see
660      * com.intel.bluetooth.BluetoothStack#l2OpenClientConnection(com.intel.bluetooth
661      * .BluetoothConnectionParams, int, int)
662      */
663     public long l2OpenClientConnection(BluetoothConnectionParams params, int receiveMTU, int transmitMTU) throws IOException {
664         validateMTU(receiveMTU, transmitMTU);
665         return l2OpenClientConnectionImpl(this.localDeviceBTAddress, params.address, params.channel, params.authenticate, params.encrypt, receiveMTU,
666                 transmitMTU, params.timeout);
667     }
668 
669     /*
670      * (non-Javadoc)
671      * 
672      * @see com.intel.bluetooth.BluetoothStack#l2CloseClientConnection(long)
673      */
674     public native void l2CloseClientConnection(long handle) throws IOException;
675 
676     private native long l2ServerOpenImpl(long localDeviceBTAddress, boolean authorize, boolean authenticate, boolean encrypt, boolean master, boolean timeouts,
677             int backlog, int receiveMTU, int transmitMTU, int assignPsm) throws IOException;
678 
679     public native int l2ServerGetPSMImpl(long handle) throws IOException;
680 
681     /*
682      * (non-Javadoc)
683      * 
684      * @seecom.intel.bluetooth.BluetoothStack#l2ServerOpen(com.intel.bluetooth.
685      * BluetoothConnectionNotifierParams, int, int,
686      * com.intel.bluetooth.ServiceRecordImpl)
687      */
688     public long l2ServerOpen(BluetoothConnectionNotifierParams params, int receiveMTU, int transmitMTU, ServiceRecordImpl serviceRecord) throws IOException {
689         validateMTU(receiveMTU, transmitMTU);
690         long socket = l2ServerOpenImpl(this.localDeviceBTAddress, params.authorize, params.authenticate, params.encrypt, params.master, params.timeouts,
691                 LISTEN_BACKLOG_L2CAP, receiveMTU, transmitMTU, params.bluecove_ext_psm);
692         boolean success = false;
693         try {
694             int channel = l2ServerGetPSMImpl(socket);
695             serviceRecord.populateL2CAPAttributes(0, channel, params.uuid, params.name);
696             registerSDPRecord(serviceRecord);
697             success = true;
698             return socket;
699         } finally {
700             if (!success) {
701                 l2ServerCloseImpl(socket, true);
702             }
703         }
704     }
705 
706     /*
707      * (non-Javadoc)
708      * 
709      * @see com.intel.bluetooth.BluetoothStack#l2ServerUpdateServiceRecord(long,
710      * com.intel.bluetooth.ServiceRecordImpl, boolean)
711      */
712     public void l2ServerUpdateServiceRecord(long handle, ServiceRecordImpl serviceRecord, boolean acceptAndOpen) throws ServiceRegistrationException {
713         updateSDPRecord(serviceRecord);
714     }
715 
716     /*
717      * (non-Javadoc)
718      * 
719      * @see
720      * com.intel.bluetooth.BluetoothStack#l2ServerAcceptAndOpenServerConnection
721      * (long)
722      */
723     public native long l2ServerAcceptAndOpenServerConnection(long handle) throws IOException;
724 
725     /*
726      * (non-Javadoc)
727      * 
728      * @see com.intel.bluetooth.BluetoothStack#l2CloseServerConnection(long)
729      */
730     public void l2CloseServerConnection(long handle) throws IOException {
731         l2CloseClientConnection(handle);
732     }
733 
734     private native void l2ServerCloseImpl(long handle, boolean quietly) throws IOException;
735 
736     /*
737      * (non-Javadoc)
738      * 
739      * @see com.intel.bluetooth.BluetoothStack#l2ServerClose(long,
740      * com.intel.bluetooth.ServiceRecordImpl)
741      */
742     public void l2ServerClose(long handle, ServiceRecordImpl serviceRecord) throws IOException {
743         try {
744             unregisterSDPRecord(serviceRecord);
745         } finally {
746             l2ServerCloseImpl(handle, false);
747         }
748 
749     }
750 
751     /*
752      * (non-Javadoc)
753      * 
754      * @see com.intel.bluetooth.BluetoothStack#l2Ready(long)
755      */
756     public native boolean l2Ready(long handle) throws IOException;
757 
758     /*
759      * (non-Javadoc)
760      * 
761      * @see com.intel.bluetooth.BluetoothStack#l2receive(long, byte[])
762      */
763     public native int l2Receive(long handle, byte[] inBuf) throws IOException;
764 
765     /*
766      * (non-Javadoc)
767      * 
768      * @see com.intel.bluetooth.BluetoothStack#l2send(long, byte[])
769      */
770     public native void l2Send(long handle, byte[] data) throws IOException;
771 
772     /*
773      * (non-Javadoc)
774      * 
775      * @see com.intel.bluetooth.BluetoothStack#l2GetReceiveMTU(long)
776      */
777     public native int l2GetReceiveMTU(long handle) throws IOException;
778 
779     /*
780      * (non-Javadoc)
781      * 
782      * @see com.intel.bluetooth.BluetoothStack#l2GetTransmitMTU(long)
783      */
784     public native int l2GetTransmitMTU(long handle) throws IOException;
785 
786     /*
787      * (non-Javadoc)
788      * 
789      * @see com.intel.bluetooth.BluetoothStack#l2RemoteAddress(long)
790      */
791     public native long l2RemoteAddress(long handle) throws IOException;
792 
793     /*
794      * (non-Javadoc)
795      * 
796      * @see com.intel.bluetooth.BluetoothStack#l2GetSecurityOpt(long, int)
797      */
798     public native int l2GetSecurityOpt(long handle, int expected) throws IOException;
799 
800     /*
801      * (non-Javadoc)
802      * 
803      * @see com.intel.bluetooth.BluetoothStack#l2Encrypt(long,long,boolean)
804      */
805     public boolean l2Encrypt(long address, long handle, boolean on) throws IOException {
806         return false;
807     }
808 }