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
26 package com.intel.bluetooth;
27
28 import java.io.IOException;
29
30 import javax.bluetooth.BluetoothStateException;
31 import javax.bluetooth.DeviceClass;
32 import javax.bluetooth.DiscoveryListener;
33 import javax.bluetooth.RemoteDevice;
34 import javax.bluetooth.ServiceRegistrationException;
35 import javax.bluetooth.UUID;
36
37 class BluetoothEmulator implements BluetoothStack {
38
39 static final int NATIVE_LIBRARY_VERSION = BlueCoveImpl.nativeLibraryVersionExpected;
40
41 private EmulatorLocalDevice localDevice;
42
43 private EmulatorDeviceInquiry deviceInquiry;
44
45 BluetoothEmulator() {
46 }
47
48
49
50 public String getStackID() {
51 return BlueCoveImpl.STACK_EMULATOR;
52 }
53
54 public String toString() {
55 if (localDevice != null) {
56 return getStackID() + ":" + RemoteDeviceHelper.getBluetoothAddress(localDevice.getAddress());
57 } else {
58 return getStackID();
59 }
60 }
61
62
63
64
65
66
67 public boolean isNativeCodeLoaded() {
68 return true;
69 }
70
71
72
73
74
75
76 public LibraryInformation[] requireNativeLibraries() {
77 return null;
78 }
79
80 public int getLibraryVersion() throws BluetoothStateException {
81 return NATIVE_LIBRARY_VERSION;
82 }
83
84 public int detectBluetoothStack() {
85 return BlueCoveImpl.BLUECOVE_STACK_DETECT_EMULATOR;
86 }
87
88 public void initialize() throws BluetoothStateException {
89 localDevice = EmulatorHelper.createNewLocalDevice();
90 }
91
92 public void destroy() {
93 EmulatorHelper.releaseDevice(localDevice);
94 localDevice = null;
95 }
96
97 public void enableNativeDebug(Class nativeDebugCallback, boolean on) {
98 }
99
100
101
102
103
104
105 public boolean isCurrentThreadInterruptedCallback() {
106 return Thread.interrupted();
107 }
108
109
110
111
112
113
114 public int getFeatureSet() {
115 return FEATURE_SET_DEVICE_SERVICE_CLASSES | FEATURE_SERVICE_ATTRIBUTES | FEATURE_L2CAP;
116 }
117
118
119
120 private void assertClosed() {
121 if (localDevice == null) {
122 throw new RuntimeException("Device Closed");
123 }
124 }
125
126 public String getLocalDeviceBluetoothAddress() throws BluetoothStateException {
127 assertClosed();
128 return RemoteDeviceHelper.getBluetoothAddress(localDevice.getAddress());
129 }
130
131 public DeviceClass getLocalDeviceClass() {
132 assertClosed();
133 return new DeviceClass(localDevice.getDeviceClass());
134 }
135
136 public String getLocalDeviceName() {
137 assertClosed();
138 return localDevice.getName();
139 }
140
141 public boolean isLocalDevicePowerOn() {
142 assertClosed();
143 return localDevice.isLocalDevicePowerOn();
144 }
145
146 public String getLocalDeviceProperty(String property) {
147 assertClosed();
148 return localDevice.getLocalDeviceProperty(property);
149 }
150
151 public int getLocalDeviceDiscoverable() {
152 assertClosed();
153 return localDevice.getLocalDeviceDiscoverable();
154 }
155
156 public boolean setLocalDeviceDiscoverable(int mode) throws BluetoothStateException {
157 assertClosed();
158 return localDevice.setLocalDeviceDiscoverable(mode);
159 }
160
161 private EmulatorLocalDevice activeLocalDevice() throws BluetoothStateException {
162 assertClosed();
163 if (!localDevice.isActive()) {
164 throw new BluetoothStateException("Bluetooth system is off");
165 }
166 return localDevice;
167 }
168
169
170
171
172
173
174 public void setLocalDeviceServiceClasses(int classOfDevice) {
175 assertClosed();
176 localDevice.setLocalDeviceServiceClasses(classOfDevice);
177 }
178
179
180
181 public boolean authenticateRemoteDevice(long address) throws IOException {
182 return false;
183 }
184
185
186
187
188
189
190 public boolean authenticateRemoteDevice(long address, String passkey) throws IOException {
191 return false;
192 }
193
194
195
196
197
198
199 public void removeAuthenticationWithRemoteDevice(long address) throws IOException {
200 throw new NotSupportedIOException(getStackID());
201 }
202
203
204
205 public boolean startInquiry(int accessCode, DiscoveryListener listener) throws BluetoothStateException {
206 if (deviceInquiry != null) {
207 throw new BluetoothStateException("Another inquiry already running");
208 }
209 deviceInquiry = new EmulatorDeviceInquiry(activeLocalDevice(), this, listener);
210 return DeviceInquiryThread.startInquiry(this, deviceInquiry, accessCode, listener);
211 }
212
213 public boolean cancelInquiry(DiscoveryListener listener) {
214 assertClosed();
215 if (deviceInquiry == null) {
216 return false;
217 }
218 if (deviceInquiry.cancelInquiry(listener)) {
219 deviceInquiry = null;
220 return true;
221 } else {
222 return false;
223 }
224 }
225
226 public String getRemoteDeviceFriendlyName(long address) throws IOException {
227 return activeLocalDevice().getDeviceManagerService().getRemoteDeviceFriendlyName(address);
228 }
229
230 public RemoteDevice[] retrieveDevices(int option) {
231 return null;
232 }
233
234 public Boolean isRemoteDeviceTrusted(long address) {
235 return null;
236 }
237
238 public Boolean isRemoteDeviceAuthenticated(long address) {
239 return null;
240 }
241
242
243
244 public int searchServices(int[] attrSet, UUID[] uuidSet, RemoteDevice device, DiscoveryListener listener)
245 throws BluetoothStateException {
246 return SearchServicesThread.startSearchServices(this, new EmulatorSearchServices(activeLocalDevice(), this),
247 attrSet, uuidSet, device, listener);
248 }
249
250 public boolean cancelServiceSearch(int transID) {
251 assertClosed();
252 SearchServicesThread sst = SearchServicesThread.getServiceSearchThread(transID);
253 if (sst != null) {
254 synchronized (sst) {
255 if (!sst.isTerminated()) {
256 sst.setTerminated();
257 return true;
258 }
259 }
260 }
261 return false;
262 }
263
264 public boolean populateServicesRecordAttributeValues(ServiceRecordImpl serviceRecord, int[] attrIDs)
265 throws IOException {
266 if (attrIDs.length > localDevice.getBluetooth_sd_attr_retrievable_max()) {
267 throw new IllegalArgumentException();
268 }
269 return EmulatorSearchServices.populateServicesRecordAttributeValues(activeLocalDevice(), serviceRecord,
270 attrIDs, RemoteDeviceHelper.getAddress(serviceRecord.getHostDevice()), serviceRecord.getHandle());
271 }
272
273
274
275 public long connectionRfOpenClientConnection(BluetoothConnectionParams params) throws IOException {
276 EmulatorRFCOMMClient c = activeLocalDevice().createRFCOMMClient(params.address);
277 boolean success = false;
278 try {
279 c.connect(params);
280 success = true;
281 } finally {
282 if (!success) {
283 localDevice.removeConnection(c);
284 }
285 }
286 return c.getHandle();
287 }
288
289 public void connectionRfCloseClientConnection(long handle) throws IOException {
290 assertClosed();
291 if (localDevice == null) {
292 return;
293 }
294 EmulatorRFCOMMClient c = ((EmulatorRFCOMMClient) localDevice.getConnection(handle));
295 try {
296 c.close();
297 } finally {
298 if (localDevice != null) {
299 localDevice.removeConnection(c);
300 }
301 }
302 }
303
304 public int rfGetSecurityOpt(long handle, int expected) throws IOException {
305 assertClosed();
306 return ((EmulatorLinkedConnection) localDevice.getConnection(handle)).getSecurityOpt(expected);
307 }
308
309
310
311
312
313
314 public boolean rfEncrypt(long address, long handle, boolean on) throws IOException {
315 assertClosed();
316 return ((EmulatorLinkedConnection) localDevice.getConnection(handle)).encrypt(address, on);
317 }
318
319
320
321 public long rfServerOpen(BluetoothConnectionNotifierParams params, ServiceRecordImpl serviceRecord)
322 throws IOException {
323 EmulatorRFCOMMService s = activeLocalDevice().createRFCOMMService();
324 boolean success = false;
325 try {
326 s.open(params);
327 serviceRecord.setHandle(s.getHandle());
328 serviceRecord
329 .populateRFCOMMAttributes(s.getHandle(), s.getChannel(), params.uuid, params.name, params.obex);
330 s.updateServiceRecord(serviceRecord);
331 success = true;
332 } finally {
333 if (!success) {
334 localDevice.removeConnection(s);
335 }
336 }
337 return s.getHandle();
338 }
339
340 public void rfServerClose(long handle, ServiceRecordImpl serviceRecord) throws IOException {
341 assertClosed();
342 if (localDevice == null) {
343 return;
344 }
345 EmulatorRFCOMMService s = ((EmulatorRFCOMMService) localDevice.getConnection(handle));
346 try {
347 s.close(serviceRecord);
348 } finally {
349 if (localDevice != null) {
350 localDevice.removeConnection(s);
351 }
352 }
353 }
354
355 private void serverUpdateServiceRecord(long handle, ServiceRecordImpl serviceRecord, boolean acceptAndOpen)
356 throws ServiceRegistrationException {
357 EmulatorServiceConnection s;
358 try {
359 s = ((EmulatorServiceConnection) activeLocalDevice().getConnection(handle));
360 } catch (IOException e) {
361 throw new ServiceRegistrationException(e.getMessage());
362 }
363 s.updateServiceRecord(serviceRecord);
364 }
365
366 public void rfServerUpdateServiceRecord(long handle, ServiceRecordImpl serviceRecord, boolean acceptAndOpen)
367 throws ServiceRegistrationException {
368 serverUpdateServiceRecord(handle, serviceRecord, acceptAndOpen);
369 }
370
371 public long rfServerAcceptAndOpenRfServerConnection(long handle) throws IOException {
372 EmulatorRFCOMMService s = ((EmulatorRFCOMMService) activeLocalDevice().getConnection(handle));
373 if (!localDevice.isConnectable()) {
374 throw new BluetoothStateException("Local device is not connectable");
375 }
376 long clientHandle = 0;
377 boolean success = false;
378 while (!success) {
379 long connectionHandle = s.accept();
380 try {
381 long remoteAddress = localDevice.getDeviceManagerService().getRemoteAddress(localDevice.getAddress(),
382 connectionHandle);
383 EmulatorRFCOMMClient c = localDevice.createRFCOMMClient(remoteAddress);
384 c.connect(remoteAddress, connectionHandle);
385 localDevice.getDeviceManagerService().connectionAccepted(localDevice.getAddress(), connectionHandle);
386 success = true;
387 clientHandle = c.getHandle();
388 } catch (IOException e) {
389 DebugLog.debug("fail to accept connection", e);
390 continue;
391 } finally {
392 if (!success) {
393 localDevice.getDeviceManagerService().closeConnection(localDevice.getAddress(), connectionHandle);
394 }
395 }
396 }
397 return clientHandle;
398 }
399
400 public void connectionRfCloseServerConnection(long handle) throws IOException {
401 connectionRfCloseClientConnection(handle);
402 }
403
404
405
406 public int connectionRfRead(long handle) throws IOException {
407 return ((EmulatorRFCOMMClient) activeLocalDevice().getConnection(handle)).read();
408 }
409
410 public int connectionRfRead(long handle, byte[] b, int off, int len) throws IOException {
411 return ((EmulatorRFCOMMClient) activeLocalDevice().getConnection(handle)).read(b, off, len);
412 }
413
414 public int connectionRfReadAvailable(long handle) throws IOException {
415 return ((EmulatorRFCOMMClient) activeLocalDevice().getConnection(handle)).available();
416 }
417
418 public void connectionRfWrite(long handle, int b) throws IOException {
419 ((EmulatorRFCOMMClient) activeLocalDevice().getConnection(handle)).write(b);
420 }
421
422 public void connectionRfWrite(long handle, byte[] b, int off, int len) throws IOException {
423 ((EmulatorRFCOMMClient) activeLocalDevice().getConnection(handle)).write(b, off, len);
424 }
425
426 public void connectionRfFlush(long handle) throws IOException {
427 ((EmulatorRFCOMMClient) activeLocalDevice().getConnection(handle)).flush();
428 }
429
430 public long getConnectionRfRemoteAddress(long handle) throws IOException {
431 return ((EmulatorRFCOMMClient) activeLocalDevice().getConnection(handle)).getRemoteAddress();
432 }
433
434
435
436 private void validateMTU(int receiveMTU, int transmitMTU) {
437 if (receiveMTU > localDevice.getBluetooth_l2cap_receiveMTU_max()) {
438 throw new IllegalArgumentException("invalid ReceiveMTU value " + receiveMTU);
439 }
440 }
441
442 public long l2OpenClientConnection(BluetoothConnectionParams params, int receiveMTU, int transmitMTU)
443 throws IOException {
444 validateMTU(receiveMTU, transmitMTU);
445 EmulatorL2CAPClient c = activeLocalDevice().createL2CAPClient(params.address);
446 boolean success = false;
447 try {
448 c.connect(params, receiveMTU, transmitMTU);
449 success = true;
450 } finally {
451 if (!success) {
452 localDevice.removeConnection(c);
453 }
454 }
455 return c.getHandle();
456 }
457
458 public void l2CloseClientConnection(long handle) throws IOException {
459 assertClosed();
460 EmulatorL2CAPClient c = ((EmulatorL2CAPClient) localDevice.getConnection(handle));
461 try {
462 c.close();
463 } finally {
464 localDevice.removeConnection(c);
465 }
466 }
467
468 public long l2ServerOpen(BluetoothConnectionNotifierParams params, int receiveMTU, int transmitMTU,
469 ServiceRecordImpl serviceRecord) throws IOException {
470 validateMTU(receiveMTU, transmitMTU);
471 EmulatorL2CAPService s = activeLocalDevice().createL2CAPService(params.bluecove_ext_psm);
472 boolean success = false;
473 try {
474 s.open(params, receiveMTU, transmitMTU);
475 serviceRecord.setHandle(s.getHandle());
476 serviceRecord.populateL2CAPAttributes((int) s.getHandle(), s.getPcm(), params.uuid, params.name);
477 s.updateServiceRecord(serviceRecord);
478 success = true;
479 } finally {
480 if (!success) {
481 localDevice.removeConnection(s);
482 }
483 }
484 return s.getHandle();
485 }
486
487 public void l2ServerUpdateServiceRecord(long handle, ServiceRecordImpl serviceRecord, boolean acceptAndOpen)
488 throws ServiceRegistrationException {
489 serverUpdateServiceRecord(handle, serviceRecord, acceptAndOpen);
490 }
491
492 public long l2ServerAcceptAndOpenServerConnection(long handle) throws IOException {
493 EmulatorL2CAPService s = ((EmulatorL2CAPService) activeLocalDevice().getConnection(handle));
494 if (!localDevice.isConnectable()) {
495 throw new BluetoothStateException("Local device is not connectable");
496 }
497 long clientHandle = 0;
498 boolean success = false;
499 while (!success) {
500 long connectionHandle = s.accept();
501 try {
502 long remoteAddress = localDevice.getDeviceManagerService().getRemoteAddress(localDevice.getAddress(),
503 connectionHandle);
504 EmulatorL2CAPClient c = localDevice.createL2CAPClient(remoteAddress);
505 c.connect(remoteAddress, connectionHandle, s.getReceiveMTU(), s.getTransmitMTU());
506 localDevice.getDeviceManagerService().connectionAccepted(localDevice.getAddress(), connectionHandle);
507 success = true;
508 clientHandle = c.getHandle();
509 } catch (IOException e) {
510 DebugLog.debug("fail to accept connection", e);
511 continue;
512 } finally {
513 if (!success) {
514 localDevice.getDeviceManagerService().closeConnection(localDevice.getAddress(), connectionHandle);
515 }
516 }
517 }
518 return clientHandle;
519 }
520
521 public void l2CloseServerConnection(long handle) throws IOException {
522 l2CloseClientConnection(handle);
523 }
524
525 public void l2ServerClose(long handle, ServiceRecordImpl serviceRecord) throws IOException {
526 assertClosed();
527 EmulatorL2CAPService s = ((EmulatorL2CAPService) localDevice.getConnection(handle));
528 try {
529 s.close(serviceRecord);
530 } finally {
531 localDevice.removeConnection(s);
532 }
533 }
534
535 public int l2GetSecurityOpt(long handle, int expected) throws IOException {
536 assertClosed();
537 return ((EmulatorLinkedConnection) localDevice.getConnection(handle)).getSecurityOpt(expected);
538 }
539
540 public boolean l2Ready(long handle) throws IOException {
541 return ((EmulatorL2CAPClient) activeLocalDevice().getConnection(handle)).ready();
542 }
543
544 public int l2Receive(long handle, byte[] inBuf) throws IOException {
545 return ((EmulatorL2CAPClient) activeLocalDevice().getConnection(handle)).receive(inBuf);
546 }
547
548 public void l2Send(long handle, byte[] data) throws IOException {
549 ((EmulatorL2CAPClient) activeLocalDevice().getConnection(handle)).send(data);
550 }
551
552 public int l2GetReceiveMTU(long handle) throws IOException {
553 return ((EmulatorL2CAPClient) activeLocalDevice().getConnection(handle)).getReceiveMTU();
554 }
555
556 public int l2GetTransmitMTU(long handle) throws IOException {
557 return ((EmulatorL2CAPClient) activeLocalDevice().getConnection(handle)).getTransmitMTU();
558 }
559
560 public long l2RemoteAddress(long handle) throws IOException {
561 return ((EmulatorL2CAPClient) activeLocalDevice().getConnection(handle)).getRemoteAddress();
562 }
563
564
565
566
567
568
569 public boolean l2Encrypt(long address, long handle, boolean on) throws IOException {
570 assertClosed();
571 return ((EmulatorLinkedConnection) localDevice.getConnection(handle)).encrypt(address, on);
572 }
573 }