1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package com.intel.bluetooth;
26
27 import java.io.ByteArrayInputStream;
28 import java.io.IOException;
29 import java.util.Enumeration;
30 import java.util.Hashtable;
31 import java.util.Vector;
32
33 import javax.bluetooth.BluetoothConnectionException;
34 import javax.bluetooth.BluetoothStateException;
35 import javax.bluetooth.DataElement;
36 import javax.bluetooth.DeviceClass;
37 import javax.bluetooth.DiscoveryAgent;
38 import javax.bluetooth.DiscoveryListener;
39 import javax.bluetooth.RemoteDevice;
40 import javax.bluetooth.ServiceRecord;
41 import javax.bluetooth.ServiceRegistrationException;
42 import javax.bluetooth.UUID;
43
44 class BluetoothStackOSX implements BluetoothStack {
45
46 public static final boolean debug = false;
47
48 private static BluetoothStackOSX singleInstance = null;
49
50
51 private final static int ATTR_RETRIEVABLE_MAX = 256;
52
53 private Vector deviceDiscoveryListeners = new Vector
54
55 private Hashtable deviceDiscoveryListenerReportedDevices = new Hashtable();
56
57 private int receive_mtu_max = -1;
58
59 private int localDeviceSupportedSoftwareVersion;
60
61 private long lastDeviceDiscoveryTime = 0;
62
63 private int localDeviceServiceClasses = 0;
64
65 private Thread localDeviceServiceClassMaintainer = null;
66
67 private static final int BLUETOOTH_SOFTWARE_VERSION_2_0_0 = 20000;
68
69 BluetoothStackOSX() {
70
71 }
72
73
74
75
76
77
78
79
80 public native boolean isNativeCodeLoaded();
81
82
83
84
85
86
87 public LibraryInformation[] requireNativeLibraries() {
88 return LibraryInformation.library(BlueCoveImpl.NATIVE_LIB_OSX);
89 }
90
91 public String getStackID() {
92 return BlueCoveImpl.STACK_OSX;
93 }
94
95 public String toString() {
96 return getStackID();
97 }
98
99
100
101
102
103
104 public int getFeatureSet() {
105 if (localDeviceSupportedSoftwareVersion >= BLUETOOTH_SOFTWARE_VERSION_2_0_0) {
106 return FEATURE_L2CAP | FEATURE_SERVICE_ATTRIBUTES | FEATURE_SET_DEVICE_SERVICE_CLASSES;
107 } else {
108 return FEATURE_L2CAP | FEATURE_SERVICE_ATTRIBUTES;
109 }
110 }
111
112 public native int getLibraryVersion();
113
114 public native int detectBluetoothStack();
115
116 private native boolean initializeImpl();
117
118 public void initialize() throws BluetoothStateException {
119 if (singleInstance != null) {
120 throw new BluetoothStateException("Only one instance of " + getStackID() + " stack supported");
121 }
122 localDeviceSupportedSoftwareVersion = getLocalDeviceSupportedSoftwareVersion();
123 DebugLog.debug("localDeviceSupportedSoftwareVersion", localDeviceSupportedSoftwareVersion);
124 if (!initializeImpl()) {
125 throw new BluetoothStateException("OS X BluetoothStack not found");
126 }
127 singleInstance = this;
128 }
129
130 public void destroy() {
131 if (localDeviceSupportedSoftwareVersion >= BLUETOOTH_SOFTWARE_VERSION_2_0_0) {
132 setLocalDeviceServiceClassesImpl(0);
133 }
134 singleInstance = null;
135 }
136
137 public native void enableNativeDebug(Class nativeDebugCallback, boolean on);
138
139
140
141
142
143
144
145 public boolean isCurrentThreadInterruptedCallback() {
146 return UtilsJavaSE.isCurrentThreadInterrupted();
147 }
148
149
150
151 public native String getLocalDeviceBluetoothAddress() throws BluetoothStateException;
152
153 public native String getLocalDeviceName();
154
155 private native int getDeviceClassImpl();
156
157 public DeviceClass getLocalDeviceClass() {
158 return new DeviceClass(getDeviceClassImpl());
159 }
160
161 private native boolean setLocalDeviceServiceClassesImpl(int classOfDevice);
162
163 private class MaintainDeviceServiceClassesThread extends Thread {
164
165 MaintainDeviceServiceClassesThread() {
166 super("MaintainDeviceServiceClassesThread");
167 }
168
169 public void run() {
170 boolean updated = true;
171 while (true) {
172 try {
173 int delay = 1000 * 120;
174 if (!updated) {
175 delay = 1000;
176 }
177 Thread.sleep(delay);
178 } catch (InterruptedException e) {
179 break;
180 }
181 if (localDeviceServiceClasses != 0) {
182 updated = setLocalDeviceServiceClassesImpl(localDeviceServiceClasses);
183 } else if (!updated) {
184 updated = true;
185 }
186 }
187 }
188 }
189
190
191
192
193
194
195 public synchronized void setLocalDeviceServiceClasses(int classOfDevice) {
196 if (localDeviceSupportedSoftwareVersion < BLUETOOTH_SOFTWARE_VERSION_2_0_0) {
197 return;
198 }
199 if (classOfDevice != localDeviceServiceClasses) {
200 setLocalDeviceServiceClassesImpl(classOfDevice);
201 }
202 localDeviceServiceClasses = classOfDevice;
203 if ((classOfDevice != 0) && (localDeviceServiceClassMaintainer == null)) {
204 localDeviceServiceClassMaintainer = new MaintainDeviceServiceClassesThread();
205 UtilsJavaSE.threadSetDaemon(localDeviceServiceClassMaintainer);
206 localDeviceServiceClassMaintainer.start();
207 }
208 }
209
210 public native boolean isLocalDevicePowerOn();
211
212 private native boolean isLocalDeviceFeatureSwitchRoles();
213
214 private native boolean isLocalDeviceFeatureParkMode();
215
216 private native int getLocalDeviceL2CAPMTUMaximum();
217
218 private native int getLocalDeviceSupportedSoftwareVersion();
219
220 private native String getLocalDeviceSoftwareVersionInfo();
221
222 private native int getLocalDeviceManufacturer();
223
224 private native String getLocalDeviceVersion();
225
226 public String getLocalDeviceProperty(String property) {
227 if (BluetoothConsts.PROPERTY_BLUETOOTH_CONNECTED_DEVICES_MAX.equals(property)) {
228 return isLocalDeviceFeatureParkMode() ? "255" : "7";
229 }
230 if (BluetoothConsts.PROPERTY_BLUETOOTH_SD_TRANS_MAX.equals(property)) {
231 return "7";
232 }
233 if (BluetoothConsts.PROPERTY_BLUETOOTH_CONNECTED_INQUIRY_SCAN.equals(property)) {
234 return BlueCoveImpl.TRUE;
235 }
236 if (BluetoothConsts.PROPERTY_BLUETOOTH_CONNECTED_PAGE_SCAN.equals(property)) {
237 return BlueCoveImpl.TRUE;
238 }
239 if (BluetoothConsts.PROPERTY_BLUETOOTH_CONNECTED_INQUIRY.equals(property)) {
240 return BlueCoveImpl.TRUE;
241 }
242 if (BluetoothConsts.PROPERTY_BLUETOOTH_CONNECTED_PAGE.equals(property)) {
243 return BlueCoveImpl.TRUE;
244 }
245
246 if (BluetoothConsts.PROPERTY_BLUETOOTH_SD_ATTR_RETRIEVABLE_MAX.equals(property)) {
247 return String.valueOf(ATTR_RETRIEVABLE_MAX);
248 }
249 if (BluetoothConsts.PROPERTY_BLUETOOTH_MASTER_SWITCH.equals(property)) {
250
251 return BlueCoveImpl.FALSE;
252 }
253 if (BluetoothConsts.PROPERTY_BLUETOOTH_L2CAP_RECEIVEMTU_MAX.equals(property)) {
254 return String.valueOf(receiveMTUMAX());
255 }
256
257 if ("bluecove.radio.version".equals(property)) {
258 return getLocalDeviceVersion();
259 }
260 if ("bluecove.radio.manufacturer".equals(property)) {
261 return String.valueOf(getLocalDeviceManufacturer());
262 }
263 if ("bluecove.stack.version".equals(property)) {
264 return getLocalDeviceSoftwareVersionInfo();
265 }
266
267 return null;
268 }
269
270 private int receiveMTUMAX() {
271 if (receive_mtu_max < 0) {
272 receive_mtu_max = getLocalDeviceL2CAPMTUMaximum();
273 }
274 return receive_mtu_max;
275 }
276
277 private native boolean getLocalDeviceDiscoverableImpl();
278
279 public int getLocalDeviceDiscoverable() {
280 if (getLocalDeviceDiscoverableImpl()) {
281 return DiscoveryAgent.GIAC;
282 } else {
283 return DiscoveryAgent.NOT_DISCOVERABLE;
284 }
285 }
286
287
288
289
290 public boolean setLocalDeviceDiscoverable(int mode) throws BluetoothStateException {
291 if (getLocalDeviceDiscoverable() == mode) {
292 return true;
293 }
294 return false;
295 }
296
297 private void verifyDeviceReady() throws BluetoothStateException {
298 if (!isLocalDevicePowerOn()) {
299 throw new BluetoothStateException("Bluetooth Device is not ready");
300 }
301 }
302
303 public RemoteDevice[] retrieveDevices(int option) {
304 return null;
305 }
306
307 public Boolean isRemoteDeviceTrusted(long address) {
308 return null;
309 }
310
311 public Boolean isRemoteDeviceAuthenticated(long address) {
312 return null;
313 }
314
315
316
317 public boolean authenticateRemoteDevice(long address) throws IOException {
318 return false;
319 }
320
321
322
323
324
325
326
327 public boolean authenticateRemoteDevice(long address, String passkey) throws IOException {
328 return false;
329 }
330
331
332
333
334
335
336
337
338 public void removeAuthenticationWithRemoteDevice(long address) throws IOException {
339 throw new NotSupportedIOException(getStackID());
340 }
341
342
343
344 public native String getRemoteDeviceFriendlyName(long address) throws IOException;
345
346 private native int runDeviceInquiryImpl(DeviceInquiryRunnable inquiryRunnable, DeviceInquiryThread startedNotify, int accessCode, int duration, DiscoveryListener listener)
347 throws BluetoothStateException;
348
349 public boolean startInquiry(int accessCode, DiscoveryListener listener) throws BluetoothStateException {
350
351
352 long sinceDiscoveryLast = System.currentTimeMillis() - lastDeviceDiscoveryTime;
353 long acceptableInterval = 7 * 1000;
354 if (sinceDiscoveryLast < acceptableInterval) {
355 try {
356 Thread.sleep(acceptableInterval - sinceDiscoveryLast);
357 } catch (InterruptedException e) {
358 throw new BluetoothStateException();
359 }
360 }
361
362 deviceDiscoveryListeners.addElement(listener);
363 deviceDiscoveryListenerReportedDevices.put(listener, new Vector());
364 DeviceInquiryRunnable inquiryRunnable = new DeviceInquiryRunnable() {
365
366 public int runDeviceInquiry(DeviceInquiryThread startedNotify, int accessCode, DiscoveryListener listener) throws BluetoothStateException {
367 try {
368 return runDeviceInquiryImpl(this, startedNotify, accessCode, DeviceInquiryThread.getConfigDeviceInquiryDuration(), listener);
369 } finally {
370 lastDeviceDiscoveryTime = System.currentTimeMillis();
371 deviceDiscoveryListeners.removeElement(listener);
372 deviceDiscoveryListenerReportedDevices.remove(listener);
373 }
374 }
375
376 public void deviceDiscoveredCallback(DiscoveryListener listener, long deviceAddr, int deviceClass, String deviceName, boolean paired) {
377 if (!deviceDiscoveryListeners.contains(listener)) {
378 return;
379 }
380
381 RemoteDevice remoteDevice = RemoteDeviceHelper.createRemoteDevice(BluetoothStackOSX.this, deviceAddr, deviceName, paired);
382 Vector reported = (Vector) deviceDiscoveryListenerReportedDevices.get(listener);
383 if (reported == null || (reported.contains(remoteDevice))) {
384 return;
385 }
386 reported.addElement(remoteDevice);
387 DeviceClass cod = new DeviceClass(deviceClass);
388 DebugLog.debug("deviceDiscoveredCallback address", remoteDevice.getBluetoothAddress());
389 DebugLog.debug("deviceDiscoveredCallback deviceClass", cod);
390 listener.deviceDiscovered(remoteDevice, cod);
391 }
392 };
393 return DeviceInquiryThread.startInquiry(this, inquiryRunnable, accessCode, listener);
394 }
395
396 private native boolean deviceInquiryCancelImpl();
397
398 public boolean cancelInquiry(DiscoveryListener listener) {
399
400 if (!deviceDiscoveryListeners.removeElement(listener)) {
401 return false;
402 }
403 return deviceInquiryCancelImpl();
404 }
405
406
407
408 private native int runSearchServicesImpl(long address, int transID) throws BluetoothStateException, SearchServicesException;
409
410 public int searchServices(int[] attrSet, UUID[] uuidSet, RemoteDevice device, DiscoveryListener listener) throws BluetoothStateException {
411
412 SearchServicesRunnable searchRunnable = new SearchServicesRunnable() {
413
414 public int runSearchServices(SearchServicesThread sst, int[] attrSet, UUID[] uuidSet, RemoteDevice device, DiscoveryListener listener)
415 throws BluetoothStateException {
416
417 sst.searchServicesStartedCallback();
418 int recordsSize;
419 try {
420 recordsSize = runSearchServicesImpl(RemoteDeviceHelper.getAddress(device), sst.getTransID());
421 } catch (SearchServicesDeviceNotReachableException e) {
422 return DiscoveryListener.SERVICE_SEARCH_DEVICE_NOT_REACHABLE;
423 } catch (SearchServicesTerminatedException e) {
424 return DiscoveryListener.SERVICE_SEARCH_TERMINATED;
425 } catch (SearchServicesException e) {
426 return DiscoveryListener.SERVICE_SEARCH_ERROR;
427 }
428 if (sst.isTerminated()) {
429 return DiscoveryListener.SERVICE_SEARCH_TERMINATED;
430 }
431 if (recordsSize == 0) {
432 return DiscoveryListener.SERVICE_SEARCH_NO_RECORDS;
433 }
434 Vector records = new Vector();
435 int[] uuidFilerAttrIDs = new int[] { BluetoothConsts.ServiceClassIDList, BluetoothConsts.ProtocolDescriptorList };
436 int[] requiredAttrIDs = new int[] { BluetoothConsts.ServiceRecordHandle, BluetoothConsts.ServiceRecordState, BluetoothConsts.ServiceID };
437 nextRecord: for (int i = 0; i < recordsSize; i++) {
438 ServiceRecordImpl sr = new ServiceRecordImpl(BluetoothStackOSX.this, device, i);
439 try {
440 sr.populateRecord(uuidFilerAttrIDs);
441
442 for (int u = 0; u < uuidSet.length; u++) {
443 if (!((sr.hasServiceClassUUID(uuidSet[u]) || sr.hasProtocolClassUUID(uuidSet[u])))) {
444 if (debug) {
445 DebugLog.debug("filtered ServiceRecord (" + i + ")", sr);
446 }
447 continue nextRecord;
448 }
449 }
450 if (debug) {
451 DebugLog.debug("accepted ServiceRecord (" + i + ")", sr);
452 }
453 records.addElement(sr);
454 sr.populateRecord(requiredAttrIDs);
455 if (attrSet != null) {
456 sr.populateRecord(attrSet);
457 }
458 DebugLog.debug("ServiceRecord (" + i + ")", sr);
459 } catch (Exception e) {
460 DebugLog.debug("populateRecord error", e);
461 }
462
463 if (sst.isTerminated()) {
464 DebugLog.debug("SERVICE_SEARCH_TERMINATED " + sst.getTransID());
465 return DiscoveryListener.SERVICE_SEARCH_TERMINATED;
466 }
467 }
468 if (records.size() != 0) {
469 DebugLog.debug("SERVICE_SEARCH_COMPLETED " + sst.getTransID());
470 ServiceRecord[] fileteredRecords = (ServiceRecord[]) Utils.vector2toArray(records, new ServiceRecord[records.size()]);
471 listener.servicesDiscovered(sst.getTransID(), fileteredRecords);
472 return DiscoveryListener.SERVICE_SEARCH_COMPLETED;
473 } else {
474 return DiscoveryListener.SERVICE_SEARCH_NO_RECORDS;
475 }
476 }
477
478 };
479 return SearchServicesThread.startSearchServices(this, searchRunnable, attrSet, uuidSet, device, listener);
480 }
481
482 private native void cancelServiceSearchImpl(int transID);
483
484 public boolean cancelServiceSearch(int transID) {
485 SearchServicesThread sst = SearchServicesThread.getServiceSearchThread(transID);
486 if (sst != null) {
487 synchronized (this) {
488 if (!sst.isTerminated()) {
489 sst.setTerminated();
490 cancelServiceSearchImpl(transID);
491 return true;
492 }
493 }
494 }
495 return false;
496 }
497
498 private native byte[] getServiceAttributeImpl(long address, long serviceRecordIndex, int attrID);
499
500 public boolean populateServicesRecordAttributeValues(ServiceRecordImpl serviceRecord, int[] attrIDs) throws IOException {
501 if (attrIDs.length > ATTR_RETRIEVABLE_MAX) {
502 throw new IllegalArgumentException();
503 }
504 boolean anyRetrived = false;
505 long address = RemoteDeviceHelper.getAddress(serviceRecord.getHostDevice());
506 for (int i = 0; i < attrIDs.length; i++) {
507 int id = attrIDs[i];
508 try {
509 byte[] blob = getServiceAttributeImpl(address, serviceRecord.getHandle(), id);
510 if (blob != null) {
511 DataElement element = (new SDPInputStream(new ByteArrayInputStream(blob))).readElement();
512 serviceRecord.populateAttributeValue(id, element);
513 anyRetrived = true;
514 if (debug) {
515 DebugLog.debug("data for attribute " + id + " Ox" + Integer.toHexString(id) + " " + element);
516 }
517 } else {
518 if (debug) {
519 DebugLog.debug("no data for attribute " + id + " Ox" + Integer.toHexString(id));
520 }
521 }
522 } catch (Throwable e) {
523 if (debug) {
524 DebugLog.error("error populate attribute " + id + " Ox" + Integer.toHexString(id), e);
525 }
526 }
527 }
528 return anyRetrived;
529 }
530
531
532
533 private native long connectionRfOpenClientConnectionImpl(long address, int channel, boolean authenticate, boolean encrypt, int timeout) throws IOException;
534
535 public long connectionRfOpenClientConnection(BluetoothConnectionParams params) throws IOException {
536 if (params.encrypt) {
537 throw new BluetoothConnectionException(BluetoothConnectionException.SECURITY_BLOCK, "encrypt mode not supported");
538 }
539 Object lock = RemoteDeviceHelper.createRemoteDevice(this, params.address, null, false);
540 synchronized (lock) {
541 return connectionRfOpenClientConnectionImpl(params.address, params.channel, params.authenticate, params.encrypt, params.timeout);
542 }
543 }
544
545 public native void connectionRfCloseClientConnection(long handle) throws IOException;
546
547 public native int rfGetSecurityOpt(long handle, int expected) throws IOException;
548
549
550
551
552
553
554 public boolean rfEncrypt(long address, long handle, boolean on) throws IOException {
555 return false;
556 }
557
558
559
560 private native long rfServerCreateImpl(byte[] uuidValue, boolean obexSrv, String name, boolean authenticate, boolean encrypt) throws IOException;
561
562 private native int rfServerGetChannelID(long handle) throws IOException;
563
564 private native void rfServerCloseImpl(long handle) throws IOException;
565
566 public long rfServerOpen(BluetoothConnectionNotifierParams params, ServiceRecordImpl serviceRecord) throws IOException {
567 verifyDeviceReady();
568 if (params.encrypt) {
569 throw new BluetoothConnectionException(BluetoothConnectionException.SECURITY_BLOCK, "encrypt mode not supported");
570 }
571 byte[] uuidValue = Utils.UUIDToByteArray(params.uuid);
572 long handle = rfServerCreateImpl(uuidValue, params.obex, params.name, params.authenticate, params.encrypt);
573 boolean success = false;
574 try {
575 int channel = rfServerGetChannelID(handle);
576 serviceRecord.populateRFCOMMAttributes(handle, channel, params.uuid, params.name, params.obex);
577 success = true;
578 } finally {
579 if (!success) {
580 rfServerCloseImpl(handle);
581 }
582 }
583 return handle;
584 }
585
586 public void rfServerClose(long handle, ServiceRecordImpl serviceRecord) throws IOException {
587 rfServerCloseImpl(handle);
588 }
589
590 public void rfServerUpdateServiceRecord(long handle, ServiceRecordImpl serviceRecord, boolean acceptAndOpen) throws ServiceRegistrationException {
591 sdpServiceUpdateServiceRecord(handle, 'R', serviceRecord);
592 }
593
594 public native long rfServerAcceptAndOpenRfServerConnection(long handle) throws IOException;
595
596 public void connectionRfCloseServerConnection(long handle) throws IOException {
597 connectionRfCloseClientConnection(handle);
598 }
599
600 private native void sdpServiceUpdateServiceRecordPublish(long handle, char handleType) throws ServiceRegistrationException;
601
602 private native void sdpServiceAddAttribute(long handle, char handleType, int attrID, int attrType, long numberValue, byte[] arrayValue)
603 throws ServiceRegistrationException;
604
605 private native void sdpServiceSequenceAttributeStart(long handle, char handleType, int attrID, int attrType) throws ServiceRegistrationException;
606
607 private native void sdpServiceSequenceAttributeEnd(long handle, char handleType, int attrID) throws ServiceRegistrationException;
608
609 private void sdpServiceAddAttribute(long handle, char handleType, int attrID, DataElement element) throws ServiceRegistrationException {
610 int type = element.getDataType();
611 switch (type) {
612 case DataElement.NULL:
613 sdpServiceAddAttribute(handle, handleType, attrID, type, 0, null);
614 break;
615 case DataElement.BOOL:
616 sdpServiceAddAttribute(handle, handleType, attrID, type, element.getBoolean() ? 1 : 0, null);
617 break;
618 case DataElement.U_INT_1:
619 case DataElement.INT_1:
620 case DataElement.U_INT_2:
621 case DataElement.INT_2:
622 case DataElement.U_INT_4:
623 case DataElement.INT_4:
624 case DataElement.INT_8:
625 sdpServiceAddAttribute(handle, handleType, attrID, type, element.getLong(), null);
626 break;
627 case DataElement.U_INT_8:
628 case DataElement.U_INT_16:
629 case DataElement.INT_16:
630 sdpServiceAddAttribute(handle, handleType, attrID, type, 0, (byte[]) element.getValue());
631 break;
632 case DataElement.UUID:
633 sdpServiceAddAttribute(handle, handleType, attrID, type, 0, Utils.UUIDToByteArray((UUID) element.getValue()));
634 break;
635 case DataElement.STRING:
636 byte[] bs = Utils.getUTF8Bytes((String) element.getValue());
637 sdpServiceAddAttribute(handle, handleType, attrID, type, 0, bs);
638 break;
639 case DataElement.URL:
640 byte[] bu = Utils.getASCIIBytes((String) element.getValue());
641 sdpServiceAddAttribute(handle, handleType, attrID, type, 0, bu);
642 break;
643 case DataElement.DATSEQ:
644 case DataElement.DATALT:
645 sdpServiceSequenceAttributeStart(handle, handleType, attrID, type);
646 for (Enumeration e = (Enumeration) element.getValue(); e.hasMoreElements();) {
647 DataElement child = (DataElement) e.nextElement();
648 sdpServiceAddAttribute(handle, handleType, -1, child);
649 }
650 sdpServiceSequenceAttributeEnd(handle, handleType, attrID);
651 break;
652 default:
653 throw new IllegalArgumentException();
654 }
655 }
656
657 private void sdpServiceUpdateServiceRecord(long handle, char handleType, ServiceRecordImpl serviceRecord) throws ServiceRegistrationException {
658 int[] ids = serviceRecord.getAttributeIDs();
659 if ((ids == null) || (ids.length == 0)) {
660 return;
661 }
662 for (int i = 0; i < ids.length; i++) {
663 int attrID = ids[i];
664 switch (attrID) {
665 case BluetoothConsts.ServiceRecordHandle:
666 continue;
667 case BluetoothConsts.ProtocolDescriptorList:
668 case BluetoothConsts.AttributeIDServiceName:
669 continue;
670 }
671 sdpServiceAddAttribute(handle, handleType, attrID, serviceRecord.getAttributeValue(attrID));
672 }
673 sdpServiceUpdateServiceRecordPublish(handle, handleType);
674 }
675
676
677
678 public void connectionRfFlush(long handle) throws IOException {
679
680 }
681
682 public native int connectionRfRead(long handle) throws IOException;
683
684 public native int connectionRfRead(long handle, byte[] b, int off, int len) throws IOException;
685
686 public native int connectionRfReadAvailable(long handle) throws IOException;
687
688 public void connectionRfWrite(long handle, int b) throws IOException {
689 byte buf[] = new byte[1];
690 buf[0] = (byte) (b & 0xFF);
691 connectionRfWrite(handle, buf, 0, 1);
692 }
693
694 public native void connectionRfWrite(long handle, byte[] b, int off, int len) throws IOException;
695
696 public native long getConnectionRfRemoteAddress(long handle) throws IOException;
697
698
699
700 private void validateMTU(int receiveMTU, int transmitMTU) {
701 if (receiveMTU > receiveMTUMAX()) {
702 throw new IllegalArgumentException("invalid ReceiveMTU value " + receiveMTU);
703 }
704 }
705
706 private native long l2OpenClientConnectionImpl(long address, int channel, boolean authenticate, boolean encrypt, int receiveMTU, int transmitMTU,
707 int timeout) throws IOException;
708
709
710
711
712
713
714
715
716 public long l2OpenClientConnection(BluetoothConnectionParams params, int receiveMTU, int transmitMTU) throws IOException {
717 validateMTU(receiveMTU, transmitMTU);
718 if (params.encrypt) {
719 throw new BluetoothConnectionException(BluetoothConnectionException.SECURITY_BLOCK, "encrypt mode not supported");
720 }
721 Object lock = RemoteDeviceHelper.createRemoteDevice(this, params.address, null, false);
722 synchronized (lock) {
723 return l2OpenClientConnectionImpl(params.address, params.channel, params.authenticate, params.encrypt, receiveMTU, transmitMTU, params.timeout);
724 }
725 }
726
727
728
729
730
731
732 public native void l2CloseClientConnection(long handle) throws IOException;
733
734 private native long l2ServerOpenImpl(byte[] uuidValue, boolean authenticate, boolean encrypt, String name, int receiveMTU, int transmitMTU, int assignPsm)
735 throws IOException;
736
737 public native int l2ServerPSM(long handle) throws IOException;
738
739
740
741
742
743
744
745
746 public long l2ServerOpen(BluetoothConnectionNotifierParams params, int receiveMTU, int transmitMTU, ServiceRecordImpl serviceRecord) throws IOException {
747 verifyDeviceReady();
748 validateMTU(receiveMTU, transmitMTU);
749 if (params.encrypt) {
750 throw new BluetoothConnectionException(BluetoothConnectionException.SECURITY_BLOCK, "encrypt mode not supported");
751 }
752 byte[] uuidValue = Utils.UUIDToByteArray(params.uuid);
753 long handle = l2ServerOpenImpl(uuidValue, params.authenticate, params.encrypt, params.name, receiveMTU, transmitMTU, params.bluecove_ext_psm);
754
755 int channel = l2ServerPSM(handle);
756
757 int serviceRecordHandle = (int) handle;
758
759 serviceRecord.populateL2CAPAttributes(serviceRecordHandle, channel, params.uuid, params.name);
760
761 return handle;
762 }
763
764
765
766
767
768
769
770 public void l2ServerUpdateServiceRecord(long handle, ServiceRecordImpl serviceRecord, boolean acceptAndOpen) throws ServiceRegistrationException {
771 sdpServiceUpdateServiceRecord(handle, 'L', serviceRecord);
772 }
773
774
775
776
777
778
779
780
781 public native long l2ServerAcceptAndOpenServerConnection(long handle) throws IOException;
782
783
784
785
786
787
788 public void l2CloseServerConnection(long handle) throws IOException {
789 l2CloseClientConnection(handle);
790 }
791
792 private native void l2ServerCloseImpl(long handle) throws IOException;
793
794
795
796
797
798
799
800 public void l2ServerClose(long handle, ServiceRecordImpl serviceRecord) throws IOException {
801 l2ServerCloseImpl(handle);
802 }
803
804
805
806
807
808
809 public native int l2GetSecurityOpt(long handle, int expected) throws IOException;
810
811
812
813
814
815
816 public native boolean l2Ready(long handle) throws IOException;
817
818
819
820
821
822
823 public native int l2Receive(long handle, byte[] inBuf) throws IOException;
824
825
826
827
828
829
830 public native void l2Send(long handle, byte[] data) throws IOException;
831
832
833
834
835
836
837 public native int l2GetReceiveMTU(long handle) throws IOException;
838
839
840
841
842
843
844 public native int l2GetTransmitMTU(long handle) throws IOException;
845
846
847
848
849
850
851 public native long l2RemoteAddress(long handle) throws IOException;
852
853
854
855
856
857
858 public boolean l2Encrypt(long address, long handle, boolean on) throws IOException {
859 return false;
860 }
861 }