1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package com.intel.bluetooth;
25
26 import java.io.ByteArrayInputStream;
27 import java.io.ByteArrayOutputStream;
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.BluetoothStateException;
34 import javax.bluetooth.DataElement;
35 import javax.bluetooth.DeviceClass;
36 import javax.bluetooth.DiscoveryAgent;
37 import javax.bluetooth.DiscoveryListener;
38 import javax.bluetooth.RemoteDevice;
39 import javax.bluetooth.ServiceRecord;
40 import javax.bluetooth.ServiceRegistrationException;
41 import javax.bluetooth.UUID;
42
43 class BluetoothStackWIDCOMM implements BluetoothStack {
44
45 private static BluetoothStackWIDCOMM singleInstance = null;
46
47 private boolean initialized = false;
48
49 private Vector deviceDiscoveryListeners = new Vector
50
51 private Hashtable deviceDiscoveryListenerFoundDevices = new Hashtable();
52
53 private Hashtable deviceDiscoveryListenerReportedDevices = new Hashtable();
54
55
56 private final static int ATTR_RETRIEVABLE_MAX = 256;
57
58 private final static int RECEIVE_MTU_MAX = 1024;
59
60
61 final static short NULL_DESC_TYPE = 0;
62
63 final static short UINT_DESC_TYPE = 1;
64
65 final static short TWO_COMP_INT_DESC_TYPE = 2;
66
67 final static short UUID_DESC_TYPE = 3;
68
69 final static short TEXT_STR_DESC_TYPE = 4;
70
71 final static short BOOLEAN_DESC_TYPE = 5;
72
73 final static short DATA_ELE_SEQ_DESC_TYPE = 6;
74
75 final static short DATA_ELE_ALT_DESC_TYPE = 7;
76
77 final static short URL_DESC_TYPE = 8;
78
79 BluetoothStackWIDCOMM() {
80 }
81
82 public String getStackID() {
83 return BlueCoveImpl.STACK_WIDCOMM;
84 }
85
86 public String toString() {
87 return getStackID();
88 }
89
90
91
92
93
94
95 public int getFeatureSet() {
96 return FEATURE_SERVICE_ATTRIBUTES | FEATURE_L2CAP;
97 }
98
99
100
101
102
103
104
105
106 public native boolean isNativeCodeLoaded();
107
108
109
110
111
112
113 public LibraryInformation[] requireNativeLibraries() {
114 return LibraryInformation.library(BlueCoveImpl.NATIVE_LIB_WIDCOMM);
115 }
116
117 public native int getLibraryVersion();
118
119 public native int detectBluetoothStack();
120
121 public native void enableNativeDebug(Class nativeDebugCallback, boolean on);
122
123 public void initialize() throws BluetoothStateException {
124 if (singleInstance != null) {
125 throw new BluetoothStateException("Only one instance of " + getStackID() + " stack supported");
126 }
127 if (!initializeImpl()) {
128 throw new RuntimeException("WIDCOMM BluetoothStack not found");
129 }
130 initialized = true;
131 singleInstance = this;
132 }
133
134 public native boolean initializeImpl();
135
136 private native void uninitialize();
137
138 public void destroy() {
139 if (singleInstance != this) {
140 throw new RuntimeException("Destroy invalid instance");
141 }
142 if (initialized) {
143 uninitialize();
144 initialized = false;
145 DebugLog.debug("WIDCOMM destroyed");
146 }
147 singleInstance = null;
148 }
149
150 protected void finalize() {
151 destroy();
152 }
153
154 public native String getLocalDeviceBluetoothAddress() throws BluetoothStateException;
155
156 public native String getLocalDeviceName();
157
158 private native int getDeviceClassImpl();
159
160
161
162
163 public DeviceClass getLocalDeviceClass() {
164 return new DeviceClass(getDeviceClassImpl());
165 }
166
167
168
169
170
171
172 public void setLocalDeviceServiceClasses(int classOfDevice) {
173 throw new NotSupportedRuntimeException(getStackID());
174 }
175
176
177
178
179
180
181
182
183
184 public boolean setLocalDeviceDiscoverable(int mode) throws BluetoothStateException {
185 int curentMode = getLocalDeviceDiscoverable();
186 if (curentMode == mode) {
187 return true;
188 } else {
189 return false;
190 }
191 }
192
193 private native boolean isStackServerUp();
194
195 private synchronized void verifyDeviceReady() throws BluetoothStateException {
196 if (!isLocalDevicePowerOn()) {
197 throw new BluetoothStateException("Bluetooth Device is not ready");
198 }
199 }
200
201 public native boolean isLocalDeviceDiscoverable();
202
203 public int getLocalDeviceDiscoverable() {
204 if (isStackServerUp() && isLocalDeviceDiscoverable()) {
205 return DiscoveryAgent.GIAC;
206 } else {
207 return DiscoveryAgent.NOT_DISCOVERABLE;
208 }
209 }
210
211 public native boolean isLocalDevicePowerOn();
212
213 private native String getBTWVersionInfo();
214
215 private native int getDeviceVersion();
216
217 private native int getDeviceManufacturer();
218
219 public String getLocalDeviceProperty(String property) {
220 if (BluetoothConsts.PROPERTY_BLUETOOTH_CONNECTED_DEVICES_MAX.equals(property)) {
221 return "7";
222 }
223 if (BluetoothConsts.PROPERTY_BLUETOOTH_SD_TRANS_MAX.equals(property)) {
224 return "1";
225 }
226 if (BluetoothConsts.PROPERTY_BLUETOOTH_CONNECTED_INQUIRY_SCAN.equals(property)) {
227 return BlueCoveImpl.TRUE;
228 }
229 if (BluetoothConsts.PROPERTY_BLUETOOTH_CONNECTED_PAGE_SCAN.equals(property)) {
230 return BlueCoveImpl.TRUE;
231 }
232 if (BluetoothConsts.PROPERTY_BLUETOOTH_CONNECTED_INQUIRY.equals(property)) {
233 return BlueCoveImpl.TRUE;
234 }
235 if (BluetoothConsts.PROPERTY_BLUETOOTH_CONNECTED_PAGE.equals(property)) {
236 return BlueCoveImpl.TRUE;
237 }
238
239 if (BluetoothConsts.PROPERTY_BLUETOOTH_SD_ATTR_RETRIEVABLE_MAX.equals(property)) {
240 return String.valueOf(ATTR_RETRIEVABLE_MAX);
241 }
242 if (BluetoothConsts.PROPERTY_BLUETOOTH_MASTER_SWITCH.equals(property)) {
243 return BlueCoveImpl.FALSE;
244 }
245 if (BluetoothConsts.PROPERTY_BLUETOOTH_L2CAP_RECEIVEMTU_MAX.equals(property)) {
246 return String.valueOf(RECEIVE_MTU_MAX);
247 }
248
249 if ("bluecove.radio.version".equals(property)) {
250 return String.valueOf(getDeviceVersion());
251 }
252 if ("bluecove.radio.manufacturer".equals(property)) {
253 return String.valueOf(getDeviceManufacturer());
254 }
255 if ("bluecove.stack.version".equals(property)) {
256 return getBTWVersionInfo();
257 }
258
259 if (property.startsWith("bluecove.nativeFunction:")) {
260 String functionDescr = property.substring(property.indexOf(':') + 1, property.length());
261 int paramIdx = functionDescr.indexOf(':');
262 if (paramIdx == -1) {
263 throw new RuntimeException("Invalid native function " + functionDescr + "; arguments expected");
264 }
265 String function = functionDescr.substring(0, paramIdx);
266 long address = RemoteDeviceHelper.getAddress(functionDescr.substring(function.length() + 1, functionDescr.length()));
267 if ("getRemoteDeviceVersionInfo".equals(function)) {
268 return getRemoteDeviceVersionInfo(address);
269 } else if ("cancelSniffMode".equals(function)) {
270 return String.valueOf(cancelSniffMode(address));
271 } else if ("setSniffMode".equals(function)) {
272 return String.valueOf(setSniffMode(address));
273 } else if ("getRemoteDeviceRSSI".equals(function)) {
274 return String.valueOf(getRemoteDeviceRSSI(address));
275 } else if ("getRemoteDeviceLinkMode".equals(function)) {
276 if (isRemoteDeviceConnected(address)) {
277 return getRemoteDeviceLinkMode(address);
278 } else {
279 return "disconnected";
280 }
281 }
282 }
283 return null;
284 }
285
286
287
288
289
290
291
292 public boolean isCurrentThreadInterruptedCallback() {
293 return UtilsJavaSE.isCurrentThreadInterrupted();
294 }
295
296 public RemoteDevice[] retrieveDevices(int option) {
297 return null;
298 }
299
300 public Boolean isRemoteDeviceTrusted(long address) {
301 return null;
302 }
303
304 public Boolean isRemoteDeviceAuthenticated(long address) {
305 return null;
306 }
307
308
309
310 public boolean authenticateRemoteDevice(long address) throws IOException {
311 return false;
312 }
313
314 private native boolean authenticateRemoteDeviceImpl(long address, String passkey) throws IOException;
315
316
317
318
319
320
321
322 public boolean authenticateRemoteDevice(long address, String passkey) throws IOException {
323 return authenticateRemoteDeviceImpl(address, passkey);
324 }
325
326 private native void removeAuthenticationWithRemoteDeviceImpl(long address) throws IOException;
327
328
329
330
331
332
333
334
335 public void removeAuthenticationWithRemoteDevice(long address) throws IOException {
336 removeAuthenticationWithRemoteDeviceImpl(address);
337 }
338
339
340
341 private native boolean isRemoteDeviceConnected(long address);
342
343 private native String getRemoteDeviceLinkMode(long address);
344
345 private native String getRemoteDeviceVersionInfo(long address);
346
347 private native boolean setSniffMode(long address);
348
349 private native boolean cancelSniffMode(long address);
350
351 private native int getRemoteDeviceRSSI(long address);
352
353
354
355 private native int runDeviceInquiryImpl(DeviceInquiryRunnable inquiryRunnable, DeviceInquiryThread startedNotify, int accessCode, DiscoveryListener listener)
356 throws BluetoothStateException;
357
358 public boolean startInquiry(int accessCode, DiscoveryListener listener) throws BluetoothStateException {
359 deviceDiscoveryListeners.addElement(listener);
360 if (BlueCoveImpl.getConfigProperty(BlueCoveConfigProperties.PROPERTY_INQUIRY_REPORT_ASAP, false)) {
361 deviceDiscoveryListenerFoundDevices.put(listener, new Hashtable());
362 }
363 deviceDiscoveryListenerReportedDevices.put(listener, new Vector());
364 DeviceInquiryRunnable inquiryRunnable = new DeviceInquiryRunnable() {
365 public int runDeviceInquiry(DeviceInquiryThread startedNotify, int accessCode, DiscoveryListener listener) throws BluetoothStateException {
366 try {
367 int discType = runDeviceInquiryImpl(this, startedNotify, accessCode, listener);
368 if (discType == DiscoveryListener.INQUIRY_COMPLETED) {
369
370 Hashtable previouslyFound = (Hashtable) deviceDiscoveryListenerFoundDevices.get(listener);
371 if (previouslyFound != null) {
372 Vector reported = (Vector) deviceDiscoveryListenerReportedDevices.get(listener);
373 for (Enumeration en = previouslyFound.keys(); en.hasMoreElements();) {
374 RemoteDevice remoteDevice = (RemoteDevice) en.nextElement();
375 if (reported.contains(remoteDevice)) {
376 continue;
377 }
378 reported.addElement(remoteDevice);
379 Integer deviceClassInt = (Integer) previouslyFound.get(remoteDevice);
380 DeviceClass deviceClass = new DeviceClass(deviceClassInt.intValue());
381 listener.deviceDiscovered(remoteDevice, deviceClass);
382
383 if (!deviceDiscoveryListeners.contains(listener)) {
384 return DiscoveryListener.INQUIRY_TERMINATED;
385 }
386 }
387 }
388 }
389 return discType;
390 } finally {
391 deviceDiscoveryListeners.removeElement(listener);
392 deviceDiscoveryListenerFoundDevices.remove(listener);
393 deviceDiscoveryListenerReportedDevices.remove(listener);
394 }
395 }
396
397
398
399
400
401
402 public void deviceDiscoveredCallback(DiscoveryListener listener, long deviceAddr, int deviceClass, String deviceName, boolean paired) {
403 DebugLog.debug("deviceDiscoveredCallback deviceName", deviceName);
404 if (!deviceDiscoveryListeners.contains(listener)) {
405 return;
406 }
407
408 RemoteDevice remoteDevice = RemoteDeviceHelper.createRemoteDevice(BluetoothStackWIDCOMM.this, deviceAddr, deviceName, paired);
409 Vector reported = (Vector) deviceDiscoveryListenerReportedDevices.get(listener);
410 if (reported == null || (reported.contains(remoteDevice))) {
411 return;
412 }
413
414 Hashtable previouslyFound = (Hashtable) deviceDiscoveryListenerFoundDevices.get(listener);
415 if (previouslyFound != null) {
416 Integer deviceClassInt = (Integer) previouslyFound.get(remoteDevice);
417 if (deviceClassInt == null) {
418 previouslyFound.put(remoteDevice, new Integer(deviceClass));
419 } else if (deviceClass != 0) {
420 previouslyFound.put(remoteDevice, new Integer(deviceClass));
421 }
422 } else {
423 DeviceClass cod = new DeviceClass(deviceClass);
424 reported.addElement(remoteDevice);
425 DebugLog.debug("deviceDiscoveredCallback address", remoteDevice.getBluetoothAddress());
426 DebugLog.debug("deviceDiscoveredCallback deviceClass", cod);
427 listener.deviceDiscovered(remoteDevice, cod);
428 }
429 }
430 };
431 return DeviceInquiryThread.startInquiry(this, inquiryRunnable, accessCode, listener);
432 }
433
434 private native boolean deviceInquiryCancelImpl();
435
436 public boolean cancelInquiry(DiscoveryListener listener) {
437
438 if (!deviceDiscoveryListeners.removeElement(listener)) {
439 return false;
440 }
441 return deviceInquiryCancelImpl();
442 }
443
444 native String getRemoteDeviceFriendlyName(long address, int majorDeviceClass, int minorDeviceClass) throws IOException;
445
446
447
448
449
450
451
452
453 native String peekRemoteDeviceFriendlyName(long address);
454
455 public String getRemoteDeviceFriendlyName(long address) throws IOException {
456 if (deviceDiscoveryListeners.size() != 0) {
457
458 return peekRemoteDeviceFriendlyName(address);
459 } else {
460
461 DiscoveryListener listener = new DiscoveryListenerAdapter();
462 if (startInquiry(DiscoveryAgent.GIAC, listener)) {
463 String name = peekRemoteDeviceFriendlyName(address);
464 cancelInquiry(listener);
465 return name;
466 }
467 }
468 return null;
469 }
470
471
472
473 private native long[] runSearchServicesImpl(SearchServicesThread startedNotify, byte[] uuidValue, long address) throws BluetoothStateException,
474 SearchServicesTerminatedException;
475
476 public int searchServices(int[] attrSet, UUID[] uuidSet, RemoteDevice device, DiscoveryListener listener) throws BluetoothStateException {
477
478 SearchServicesRunnable searchRunnable = new SearchServicesRunnable() {
479
480 public int runSearchServices(SearchServicesThread sst, int[] attrSet, UUID[] uuidSet, RemoteDevice device, DiscoveryListener listener)
481 throws BluetoothStateException {
482
483 synchronized (BluetoothStackWIDCOMM.class) {
484 byte[] uuidValue = Utils.UUIDToByteArray(BluetoothConsts.L2CAP_PROTOCOL_UUID);
485 for (int u = 0; u < uuidSet.length; u++) {
486 if (uuidSet[u].equals(BluetoothConsts.L2CAP_PROTOCOL_UUID)) {
487 continue;
488 } else if (uuidSet[u].equals(BluetoothConsts.RFCOMM_PROTOCOL_UUID)) {
489 uuidValue = Utils.UUIDToByteArray(uuidSet[u]);
490 continue;
491 } else {
492
493 uuidValue = Utils.UUIDToByteArray(uuidSet[u]);
494 break;
495 }
496 }
497 long[] handles;
498 try {
499 handles = runSearchServicesImpl(sst, uuidValue, RemoteDeviceHelper.getAddress(device));
500 } catch (SearchServicesTerminatedException e) {
501 DebugLog.debug("SERVICE_SEARCH_TERMINATED");
502 return DiscoveryListener.SERVICE_SEARCH_TERMINATED;
503 }
504 if (handles == null) {
505 DebugLog.debug("SERVICE_SEARCH_ERROR");
506 return DiscoveryListener.SERVICE_SEARCH_ERROR;
507 } else if (handles.length > 0) {
508 Vector records = new Vector();
509 int[] uuidFilerAttrIDs = new int[] { BluetoothConsts.ServiceClassIDList, BluetoothConsts.ProtocolDescriptorList };
510 int[] requiredAttrIDs = new int[] { BluetoothConsts.ServiceRecordHandle, BluetoothConsts.ServiceRecordState, BluetoothConsts.ServiceID };
511 nextRecord: for (int i = 0; i < handles.length; i++) {
512 ServiceRecordImpl sr = new ServiceRecordImpl(BluetoothStackWIDCOMM.this, device, handles[i]);
513 try {
514 sr.populateRecord(uuidFilerAttrIDs);
515
516 for (int u = 0; u < uuidSet.length; u++) {
517 if (!((sr.hasServiceClassUUID(uuidSet[u]) || sr.hasProtocolClassUUID(uuidSet[u])))) {
518 if (BluetoothStackWIDCOMMSDPInputStream.debug) {
519 DebugLog.debug("filtered ServiceRecord (" + i + ")", sr);
520 }
521 continue nextRecord;
522 }
523 }
524 if (BluetoothStackWIDCOMMSDPInputStream.debug) {
525 DebugLog.debug("accepted ServiceRecord (" + i + ")", sr);
526 }
527 if (!isServiceRecordDiscoverable(RemoteDeviceHelper.getAddress(device), sr.getHandle())) {
528 continue;
529 }
530
531 records.addElement(sr);
532 sr.populateRecord(requiredAttrIDs);
533 if (attrSet != null) {
534 sr.populateRecord(attrSet);
535 }
536 DebugLog.debug("ServiceRecord (" + i + ") sr.handle", handles[i]);
537 DebugLog.debug("ServiceRecord (" + i + ")", sr);
538 } catch (Exception e) {
539 DebugLog.debug("populateRecord error", e);
540 }
541 if (sst.isTerminated()) {
542 DebugLog.debug("SERVICE_SEARCH_TERMINATED");
543 return DiscoveryListener.SERVICE_SEARCH_TERMINATED;
544 }
545 }
546 if (records.size() != 0) {
547 DebugLog.debug("SERVICE_SEARCH_COMPLETED");
548 ServiceRecord[] fileteredRecords = (ServiceRecord[]) Utils.vector2toArray(records, new ServiceRecord[records.size()]);
549 listener.servicesDiscovered(sst.getTransID(), fileteredRecords);
550 return DiscoveryListener.SERVICE_SEARCH_COMPLETED;
551 }
552 }
553 DebugLog.debug("SERVICE_SEARCH_NO_RECORDS");
554 return DiscoveryListener.SERVICE_SEARCH_NO_RECORDS;
555 }
556 }
557 };
558 return SearchServicesThread.startSearchServices(this, searchRunnable, attrSet, uuidSet, device, listener);
559 }
560
561
562
563
564 private native void cancelServiceSearchImpl();
565
566 public boolean cancelServiceSearch(int transID) {
567 SearchServicesThread sst = SearchServicesThread.getServiceSearchThread(transID);
568 if (sst != null) {
569 synchronized (this) {
570 if (!sst.isTerminated()) {
571 sst.setTerminated();
572 cancelServiceSearchImpl();
573 return true;
574 }
575 }
576 }
577 return false;
578 }
579
580 private native byte[] getServiceAttribute(int attrID, long handle) throws IOException;
581
582 private native boolean isServiceRecordDiscoverable(long address, long handle) throws IOException;
583
584 public boolean populateServicesRecordAttributeValues(ServiceRecordImpl serviceRecord, int[] attrIDs) throws IOException {
585 if (attrIDs.length > ATTR_RETRIEVABLE_MAX) {
586 throw new IllegalArgumentException();
587 }
588 boolean anyRetrived = false;
589 for (int i = 0; i < attrIDs.length; i++) {
590 int id = attrIDs[i];
591 try {
592 byte[] sdpStruct = getServiceAttribute(id, serviceRecord.getHandle());
593 if (sdpStruct != null) {
594 if (BluetoothStackWIDCOMMSDPInputStream.debug) {
595 DebugLog.debug("decode attribute " + id + " Ox" + Integer.toHexString(id));
596 }
597 DataElement element = (new BluetoothStackWIDCOMMSDPInputStream(new ByteArrayInputStream(sdpStruct))).readElement();
598
599
600
601 if (id == BluetoothConsts.ProtocolDescriptorList) {
602 Enumeration protocolsSeqEnum = (Enumeration) element.getValue();
603 if (protocolsSeqEnum.hasMoreElements()) {
604 DataElement protocolElement = (DataElement) protocolsSeqEnum.nextElement();
605 if (protocolElement.getDataType() != DataElement.DATSEQ) {
606 DataElement newMainSeq = new DataElement(DataElement.DATSEQ);
607 newMainSeq.addElement(element);
608 element = newMainSeq;
609 }
610 }
611 }
612
613 serviceRecord.populateAttributeValue(id, element);
614 anyRetrived = true;
615 } else {
616 if (BluetoothStackWIDCOMMSDPInputStream.debug) {
617 DebugLog.debug("no data for attribute " + id + " Ox" + Integer.toHexString(id));
618 }
619 }
620 } catch (Throwable e) {
621 if (BluetoothStackWIDCOMMSDPInputStream.debug) {
622 DebugLog.error("error populate attribute " + id + " Ox" + Integer.toHexString(id), e);
623 }
624 }
625 }
626 return anyRetrived;
627 }
628
629
630
631 private native long connectionRfOpenClientConnectionImpl(long address, int channel, boolean authenticate, boolean encrypt, int timeout) throws IOException;
632
633 public long connectionRfOpenClientConnection(BluetoothConnectionParams params) throws IOException {
634 verifyDeviceReady();
635 return connectionRfOpenClientConnectionImpl(params.address, params.channel, params.authenticate, params.encrypt, params.timeout);
636 }
637
638 private native void closeRfCommPortImpl(long handle) throws IOException;
639
640 public void connectionRfCloseClientConnection(long handle) throws IOException {
641 closeRfCommPortImpl(handle);
642 }
643
644 public native long getConnectionRfRemoteAddress(long handle) throws IOException;
645
646 public native int connectionRfRead(long handle) throws IOException;
647
648 public native int connectionRfRead(long handle, byte[] b, int off, int len) throws IOException;
649
650 public native int connectionRfReadAvailable(long handle) throws IOException;
651
652 private native void connectionRfWriteImpl(long handle, byte[] b, int off, int len) throws IOException;
653
654 public void connectionRfWrite(long handle, int b) throws IOException {
655 byte buf[] = new byte[1];
656 buf[0] = (byte) (b & 0xFF);
657 connectionRfWriteImpl(handle, buf, 0, 1);
658 }
659
660 public void connectionRfWrite(long handle, byte[] b, int off, int len) throws IOException {
661
662 final int maxNativeBuffer = 0x10000 - 1;
663 if (len < maxNativeBuffer) {
664 connectionRfWriteImpl(handle, b, off, len);
665 } else {
666 int done = 0;
667 while (done < len) {
668 int l = len - done;
669 if (l > maxNativeBuffer) {
670 l = maxNativeBuffer;
671 }
672 connectionRfWriteImpl(handle, b, off + done, l);
673 done += maxNativeBuffer;
674 }
675 }
676 }
677
678 public void connectionRfFlush(long handle) throws IOException {
679
680 }
681
682 public int rfGetSecurityOpt(long handle, int expected) throws IOException {
683 return expected;
684 }
685
686
687
688
689
690
691 public boolean rfEncrypt(long address, long handle, boolean on) throws IOException {
692 return false;
693 }
694
695 private native synchronized long rfServerOpenImpl(byte[] uuidValue, byte[] uuidValue2, boolean obexSrv, String name, boolean authenticate, boolean encrypt)
696 throws IOException;
697
698 private native int rfServerSCN(long handle) throws IOException;
699
700 public long rfServerOpen(BluetoothConnectionNotifierParams params, ServiceRecordImpl serviceRecord) throws IOException {
701 verifyDeviceReady();
702 byte[] uuidValue = Utils.UUIDToByteArray(params.uuid);
703 byte[] uuidValue2 = params.obex ? null : Utils.UUIDToByteArray(BluetoothConsts.SERIAL_PORT_UUID);
704 long handle = rfServerOpenImpl(uuidValue, uuidValue2, params.obex, params.name, params.authenticate, params.encrypt);
705 int channel = rfServerSCN(handle);
706 DebugLog.debug("serverSCN", channel);
707 long serviceRecordHandle = handle;
708
709 serviceRecord.populateRFCOMMAttributes(serviceRecordHandle, channel, params.uuid, params.name, params.obex);
710
711 return handle;
712 }
713
714 private native void sdpServiceAddAttribute(long handle, char handleType, int attrID, short attrType, byte[] value) throws ServiceRegistrationException;
715
716 private byte[] long2byte(long value, int len) {
717 byte[] cvalue = new byte[len];
718 long l = value;
719 for (int i = len - 1; i >= 0; i--) {
720 cvalue[i] = (byte) (l & 0xFF);
721 l >>= 8;
722 }
723 return cvalue;
724 }
725
726 public void rfServerUpdateServiceRecord(long handle, ServiceRecordImpl serviceRecord, boolean acceptAndOpen) throws ServiceRegistrationException {
727 sdpServiceUpdateServiceRecord(handle, 'r', serviceRecord);
728 }
729
730 private byte[] sdpServiceSequenceAttribute(Enumeration en) throws ServiceRegistrationException {
731 ByteArrayOutputStream out = new ByteArrayOutputStream();
732 SDPOutputStream sdpOut = new SDPOutputStream(out);
733 try {
734 while (en.hasMoreElements()) {
735 sdpOut.writeElement((DataElement) en.nextElement());
736 }
737 } catch (IOException e) {
738 throw new ServiceRegistrationException(e.getMessage());
739 }
740 return out.toByteArray();
741 }
742
743 private native void sdpServiceAddServiceClassIdList(long handle, char handleType, byte[][] uuidValues) throws ServiceRegistrationException;
744
745 private void sdpServiceUpdateServiceRecord(long handle, char handleType, ServiceRecordImpl serviceRecord) throws ServiceRegistrationException {
746 int[] ids = serviceRecord.getAttributeIDs();
747 if ((ids == null) || (ids.length == 0)) {
748 return;
749 }
750
751 DataElement serviceClassIDList = serviceRecord.getAttributeValue(BluetoothConsts.ServiceClassIDList);
752 if (serviceClassIDList.getDataType() != DataElement.DATSEQ) {
753 throw new ServiceRegistrationException("Invalid serviceClassIDList");
754 }
755 Enumeration en = (Enumeration) serviceClassIDList.getValue();
756 Vector uuids = new Vector();
757 while (en.hasMoreElements()) {
758 DataElement u = (DataElement) en.nextElement();
759 if (u.getDataType() != DataElement.UUID) {
760 throw new ServiceRegistrationException("Invalid serviceClassIDList element " + u);
761 }
762 uuids.add(u.getValue());
763 }
764 if (uuids.size() > 0) {
765 byte[][] uuidValues = new byte[uuids.size()][];
766 for (int u = 0; u < uuidValues.length; u++) {
767 uuidValues[u] = Utils.UUIDToByteArray((UUID) uuids.elementAt(u));
768 }
769 sdpServiceAddServiceClassIdList(handle, handleType, uuidValues);
770 }
771
772
773 for (int i = 0; i < ids.length; i++) {
774 int id = ids[i];
775 switch (id) {
776 case BluetoothConsts.ServiceRecordHandle:
777 case BluetoothConsts.ServiceClassIDList:
778 case BluetoothConsts.ProtocolDescriptorList:
779 case BluetoothConsts.AttributeIDServiceName:
780 continue;
781 }
782
783 DataElement d = serviceRecord.getAttributeValue(id);
784 switch (d.getDataType()) {
785 case DataElement.U_INT_1:
786 sdpServiceAddAttribute(handle, handleType, id, UINT_DESC_TYPE, long2byte(d.getLong(), 1));
787 break;
788 case DataElement.U_INT_2:
789 sdpServiceAddAttribute(handle, handleType, id, UINT_DESC_TYPE, long2byte(d.getLong(), 2));
790 break;
791 case DataElement.U_INT_4:
792 sdpServiceAddAttribute(handle, handleType, id, UINT_DESC_TYPE, long2byte(d.getLong(), 4));
793 break;
794 case DataElement.U_INT_8:
795 case DataElement.U_INT_16:
796 sdpServiceAddAttribute(handle, handleType, id, UINT_DESC_TYPE, (byte[]) d.getValue());
797 break;
798 case DataElement.INT_1:
799 sdpServiceAddAttribute(handle, handleType, id, TWO_COMP_INT_DESC_TYPE, long2byte(d.getLong(), 1));
800 break;
801 case DataElement.INT_2:
802 sdpServiceAddAttribute(handle, handleType, id, TWO_COMP_INT_DESC_TYPE, long2byte(d.getLong(), 2));
803 break;
804 case DataElement.INT_4:
805 sdpServiceAddAttribute(handle, handleType, id, TWO_COMP_INT_DESC_TYPE, long2byte(d.getLong(), 4));
806 break;
807 case DataElement.INT_8:
808 sdpServiceAddAttribute(handle, handleType, id, TWO_COMP_INT_DESC_TYPE, long2byte(d.getLong(), 8));
809 break;
810 case DataElement.INT_16:
811 sdpServiceAddAttribute(handle, handleType, id, TWO_COMP_INT_DESC_TYPE, (byte[]) d.getValue());
812 break;
813 case DataElement.URL:
814 sdpServiceAddAttribute(handle, handleType, id, URL_DESC_TYPE, Utils.getASCIIBytes(d.getValue().toString()));
815 break;
816 case DataElement.STRING:
817 sdpServiceAddAttribute(handle, handleType, id, TEXT_STR_DESC_TYPE, Utils.getUTF8Bytes(d.getValue().toString()));
818 break;
819 case DataElement.NULL:
820 sdpServiceAddAttribute(handle, handleType, id, NULL_DESC_TYPE, null);
821 break;
822 case DataElement.BOOL:
823 sdpServiceAddAttribute(handle, handleType, id, BOOLEAN_DESC_TYPE, new byte[] { (byte) (d.getBoolean() ? 1 : 0) });
824 break;
825 case DataElement.UUID:
826 sdpServiceAddAttribute(handle, handleType, id, UUID_DESC_TYPE, BluetoothStackWIDCOMMSDPInputStream.getUUIDHexBytes((UUID) d.getValue()));
827 break;
828 case DataElement.DATSEQ:
829 sdpServiceAddAttribute(handle, handleType, id, DATA_ELE_SEQ_DESC_TYPE, sdpServiceSequenceAttribute((Enumeration) d.getValue()));
830 break;
831 case DataElement.DATALT:
832 sdpServiceAddAttribute(handle, handleType, id, DATA_ELE_ALT_DESC_TYPE, sdpServiceSequenceAttribute((Enumeration) d.getValue()));
833 break;
834 default:
835 throw new ServiceRegistrationException("Invalid " + d.getDataType());
836 }
837 }
838 }
839
840 public native long rfServerAcceptAndOpenRfServerConnection(long handle) throws IOException;
841
842 public native void connectionRfCloseServerConnection(long handle) throws IOException;
843
844 private native void rfServerCloseImpl(long handle) throws IOException;
845
846 public void rfServerClose(long handle, ServiceRecordImpl serviceRecord) throws IOException {
847 rfServerCloseImpl(handle);
848 }
849
850
851
852 private void validateMTU(int receiveMTU, int transmitMTU) {
853 if (receiveMTU > RECEIVE_MTU_MAX) {
854 throw new IllegalArgumentException("invalid ReceiveMTU value " + receiveMTU);
855 }
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870 }
871
872 private native long l2OpenClientConnectionImpl(long address, int channel, boolean authenticate, boolean encrypt, int receiveMTU, int transmitMTU,
873 int timeout) throws IOException;
874
875
876
877
878
879
880
881
882 public long l2OpenClientConnection(BluetoothConnectionParams params, int receiveMTU, int transmitMTU) throws IOException {
883 verifyDeviceReady();
884 validateMTU(receiveMTU, transmitMTU);
885 return l2OpenClientConnectionImpl(params.address, params.channel, params.authenticate, params.encrypt, receiveMTU, transmitMTU, params.timeout);
886 }
887
888
889
890
891
892
893 public native void l2CloseClientConnection(long handle) throws IOException;
894
895 private native synchronized long l2ServerOpenImpl(byte[] uuidValue, boolean authenticate, boolean encrypt, String name, int receiveMTU, int transmitMTU,
896 int assignPsm) throws IOException;
897
898 public native int l2ServerPSM(long handle) throws IOException;
899
900
901
902
903
904
905
906
907 public long l2ServerOpen(BluetoothConnectionNotifierParams params, int receiveMTU, int transmitMTU, ServiceRecordImpl serviceRecord) throws IOException {
908 verifyDeviceReady();
909 validateMTU(receiveMTU, transmitMTU);
910 byte[] uuidValue = Utils.UUIDToByteArray(params.uuid);
911 long handle = l2ServerOpenImpl(uuidValue, params.authenticate, params.encrypt, params.name, receiveMTU, transmitMTU, params.bluecove_ext_psm);
912
913 int channel = l2ServerPSM(handle);
914
915 int serviceRecordHandle = (int) handle;
916
917 serviceRecord.populateL2CAPAttributes(serviceRecordHandle, channel, params.uuid, params.name);
918
919 return handle;
920 }
921
922
923
924
925
926
927
928 public void l2ServerUpdateServiceRecord(long handle, ServiceRecordImpl serviceRecord, boolean acceptAndOpen) throws ServiceRegistrationException {
929 sdpServiceUpdateServiceRecord(handle, 'l', serviceRecord);
930 }
931
932
933
934
935
936
937
938
939 public native long l2ServerAcceptAndOpenServerConnection(long handle) throws IOException;
940
941
942
943
944
945
946 public native void l2CloseServerConnection(long handle) throws IOException;
947
948 private native void l2ServerCloseImpl(long handle) throws IOException;
949
950
951
952
953
954
955
956 public void l2ServerClose(long handle, ServiceRecordImpl serviceRecord) throws IOException {
957 l2ServerCloseImpl(handle);
958 }
959
960
961
962
963
964
965 public int l2GetSecurityOpt(long handle, int expected) throws IOException {
966 return expected;
967 }
968
969
970
971
972
973
974 public native int l2GetReceiveMTU(long handle) throws IOException;
975
976
977
978
979
980
981 public native int l2GetTransmitMTU(long handle) throws IOException;
982
983
984
985
986
987
988 public native boolean l2Ready(long handle) throws IOException;
989
990
991
992
993
994
995 public native int l2Receive(long handle, byte[] inBuf) throws IOException;
996
997
998
999
1000
1001
1002 public native void l2Send(long handle, byte[] data) throws IOException;
1003
1004
1005
1006
1007
1008
1009 public native long l2RemoteAddress(long handle) throws IOException;
1010
1011
1012
1013
1014
1015
1016 public boolean l2Encrypt(long address, long handle, boolean on) throws IOException {
1017 return false;
1018 }
1019 }