View Javadoc

1   /**
2    *  BlueCove - Java library for Bluetooth
3    *  Copyright (C) 2006-2008 Vlad Skarzhevskyy
4    *
5    *  Licensed to the Apache Software Foundation (ASF) under one
6    *  or more contributor license agreements.  See the NOTICE file
7    *  distributed with this work for additional information
8    *  regarding copyright ownership.  The ASF licenses this file
9    *  to you under the Apache License, Version 2.0 (the
10   *  "License"); you may not use this file except in compliance
11   *  with the License.  You may obtain a copy of the License at
12   *
13   *    http://www.apache.org/licenses/LICENSE-2.0
14   *
15   *  Unless required by applicable law or agreed to in writing,
16   *  software distributed under the License is distributed on an
17   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18   *  KIND, either express or implied.  See the License for the
19   *  specific language governing permissions and limitations
20   *  under the License.
21   *
22   *  @version $Id: BluetoothStackBlueSoleil.java 2525 2008-12-09 03:48:51Z skarzhevskyy $
23   */
24  package com.intel.bluetooth;
25  
26  import java.io.IOException;
27  
28  import javax.bluetooth.BluetoothStateException;
29  import javax.bluetooth.DeviceClass;
30  import javax.bluetooth.DiscoveryAgent;
31  import javax.bluetooth.DiscoveryListener;
32  import javax.bluetooth.RemoteDevice;
33  import javax.bluetooth.ServiceRecord;
34  import javax.bluetooth.ServiceRegistrationException;
35  import javax.bluetooth.UUID;
36  
37  class BluetoothStackBlueSoleil implements BluetoothStack, DeviceInquiryRunnable, SearchServicesRunnable {
38  
39  	private static BluetoothStackBlueSoleil singleInstance = null;
40  
41  	private boolean initialized = false;
42  
43  	private DiscoveryListener currentDeviceDiscoveryListener;
44  
45  	BluetoothStackBlueSoleil() {
46  	}
47  
48  	public String getStackID() {
49  		return BlueCoveImpl.STACK_BLUESOLEIL;
50  	}
51  
52  	public String toString() {
53  		return getStackID();
54  	}
55  
56  	// ---------------------- Library initialization
57  
58  	/*
59  	 * (non-Javadoc)
60  	 * 
61  	 * @see com.intel.bluetooth.BluetoothStack#isNativeCodeLoaded()
62  	 */
63  	public native boolean isNativeCodeLoaded();
64  
65  	/*
66  	 * (non-Javadoc)
67  	 * 
68  	 * @see com.intel.bluetooth.BluetoothStack#requireNativeLibraries()
69  	 */
70  	public LibraryInformation[] requireNativeLibraries() {
71  		return LibraryInformation.library(BlueCoveImpl.NATIVE_LIB_BLUESOLEIL);
72  	}
73  
74  	public native int getLibraryVersion();
75  
76  	public native int detectBluetoothStack();
77  
78  	public native void enableNativeDebug(Class nativeDebugCallback, boolean on);
79  
80  	public native boolean initializeImpl();
81  
82  	public void initialize() throws BluetoothStateException {
83  		if (singleInstance != null) {
84  			throw new BluetoothStateException("Only one instance of " + getStackID() + " stack supported");
85  		}
86  		if (!initializeImpl()) {
87  			DebugLog.fatal("Can't initialize BlueSoleil");
88  			throw new BluetoothStateException("BlueSoleil BluetoothStack not found");
89  		}
90  		initialized = true;
91  		singleInstance = this;
92  	}
93  
94  	private native void uninitialize();
95  
96  	public void destroy() {
97  		if (singleInstance != this) {
98  			throw new RuntimeException("Destroy invalid instance");
99  		}
100 		if (initialized) {
101 			uninitialize();
102 			initialized = false;
103 			DebugLog.debug("BlueSoleil destroyed");
104 		}
105 		singleInstance = null;
106 	}
107 
108 	protected void finalize() {
109 		destroy();
110 	}
111 
112 	public native String getLocalDeviceBluetoothAddress();
113 
114 	public native String getLocalDeviceName();
115 
116 	public native int getDeviceClassImpl();
117 
118 	/**
119 	 * There are no functions in BlueSoleil stack.
120 	 */
121 	public DeviceClass getLocalDeviceClass() {
122 		return new DeviceClass(getDeviceClassImpl());
123 	}
124 
125 	/*
126 	 * (non-Javadoc)
127 	 * 
128 	 * @see com.intel.bluetooth.BluetoothStack#setLocalDeviceServiceClasses(int)
129 	 */
130 	public void setLocalDeviceServiceClasses(int classOfDevice) {
131 		throw new NotSupportedRuntimeException(getStackID());
132 	}
133 
134 	/**
135 	 * There are no functions to set BlueSoleil stack discoverable status.
136 	 */
137 	public boolean setLocalDeviceDiscoverable(int mode) throws BluetoothStateException {
138 		return true;
139 	}
140 
141 	native boolean isBlueSoleilStarted(int seconds);
142 
143 	private native boolean isBluetoothReady(int seconds);
144 
145 	/**
146 	 * There are no functions to find BlueSoleil discoverable status.
147 	 */
148 	public int getLocalDeviceDiscoverable() {
149 		if (isBluetoothReady(2)) {
150 			return DiscoveryAgent.GIAC;
151 		} else {
152 			return DiscoveryAgent.NOT_DISCOVERABLE;
153 		}
154 	}
155 
156 	public boolean isLocalDevicePowerOn() {
157 		return isBluetoothReady(15);
158 	}
159 
160 	native int getStackVersionInfo();
161 
162 	native int getDeviceVersion();
163 
164 	native int getDeviceManufacturer();
165 
166 	/*
167 	 * (non-Javadoc)
168 	 * 
169 	 * @see com.intel.bluetooth.BluetoothStack#getFeatureSet()
170 	 */
171 	public int getFeatureSet() {
172 		return 0;
173 	}
174 
175 	public String getLocalDeviceProperty(String property) {
176 		if (BluetoothConsts.PROPERTY_BLUETOOTH_CONNECTED_DEVICES_MAX.equals(property)) {
177 			return "7";
178 		}
179 		if (BluetoothConsts.PROPERTY_BLUETOOTH_SD_TRANS_MAX.equals(property)) {
180 			return "1";
181 		}
182 		if (BluetoothConsts.PROPERTY_BLUETOOTH_CONNECTED_INQUIRY_SCAN.equals(property)) {
183 			return BlueCoveImpl.TRUE;
184 		}
185 		if (BluetoothConsts.PROPERTY_BLUETOOTH_CONNECTED_PAGE_SCAN.equals(property)) {
186 			return BlueCoveImpl.TRUE;
187 		}
188 		if (BluetoothConsts.PROPERTY_BLUETOOTH_CONNECTED_INQUIRY.equals(property)) {
189 			return BlueCoveImpl.TRUE;
190 		}
191 
192 		// service attributes are not supported.
193 		if (BluetoothConsts.PROPERTY_BLUETOOTH_SD_ATTR_RETRIEVABLE_MAX.equals(property)) {
194 			return "0";
195 		}
196 
197 		// if ("bluecove.radio.version".equals(property)) {
198 		// return String.valueOf(getDeviceVersion());
199 		// }
200 		// if ("bluecove.radio.manufacturer".equals(property)) {
201 		// return String.valueOf(getDeviceManufacturer());
202 		// }
203 		if ("bluecove.stack.version".equals(property)) {
204 			return String.valueOf(getStackVersionInfo());
205 		}
206 
207 		return null;
208 	}
209 
210 	/*
211 	 * (non-Javadoc)
212 	 * 
213 	 * @see com.intel.bluetooth.BluetoothStack#isCurrentThreadInterruptedCallback()
214 	 */
215 	public boolean isCurrentThreadInterruptedCallback() {
216 		return UtilsJavaSE.isCurrentThreadInterrupted();
217 	}
218 
219 	public RemoteDevice[] retrieveDevices(int option) {
220 		return null;
221 	}
222 
223 	public Boolean isRemoteDeviceTrusted(long address) {
224 		return null;
225 	}
226 
227 	public Boolean isRemoteDeviceAuthenticated(long address) {
228 		return null;
229 	}
230 
231 	public boolean authenticateRemoteDevice(long address) throws IOException {
232 		return false;
233 	}
234 
235 	public boolean authenticateRemoteDevice(long address, String passkey) throws IOException {
236 		return false;
237 	}
238 
239 	/*
240 	 * (non-Javadoc)
241 	 * 
242 	 * @see com.intel.bluetooth.BluetoothStack#removeAuthenticationWithRemoteDevice (long)
243 	 */
244 	public void removeAuthenticationWithRemoteDevice(long address) throws IOException {
245 		throw new NotSupportedIOException(getStackID());
246 	}
247 
248 	// --- Device Inquiry
249 
250 	public boolean startInquiry(int accessCode, DiscoveryListener listener) throws BluetoothStateException {
251 		if (currentDeviceDiscoveryListener != null) {
252 			throw new BluetoothStateException("Another inquiry already running");
253 		}
254 		currentDeviceDiscoveryListener = listener;
255 		return DeviceInquiryThread.startInquiry(this, this, accessCode, listener);
256 	}
257 
258 	public int runDeviceInquiry(DeviceInquiryThread startedNotify, int accessCode, DiscoveryListener listener)
259 			throws BluetoothStateException {
260 		try {
261 			startedNotify.deviceInquiryStartedCallback();
262 			return runDeviceInquiryImpl(startedNotify, accessCode, listener);
263 		} finally {
264 			currentDeviceDiscoveryListener = null;
265 		}
266 	}
267 
268 	public native int runDeviceInquiryImpl(DeviceInquiryThread startedNotify, int accessCode, DiscoveryListener listener)
269 			throws BluetoothStateException;
270 
271 	public void deviceDiscoveredCallback(DiscoveryListener listener, long deviceAddr, int deviceClass,
272 			String deviceName, boolean paired) {
273 		DebugLog.debug("deviceDiscoveredCallback", deviceName);
274 		RemoteDevice remoteDevice = RemoteDeviceHelper.createRemoteDevice(this, deviceAddr, deviceName, paired);
275 		if ((currentDeviceDiscoveryListener == null) || (currentDeviceDiscoveryListener != listener)) {
276 			return;
277 		}
278 		listener.deviceDiscovered(remoteDevice, new DeviceClass(deviceClass));
279 	}
280 
281 	public native boolean cancelInquirympl();
282 
283 	public boolean cancelInquiry(DiscoveryListener listener) {
284 		if (currentDeviceDiscoveryListener != listener) {
285 			return false;
286 		}
287 		// no further deviceDiscovered() events will occur for this inquiry
288 		currentDeviceDiscoveryListener = null;
289 		return cancelInquirympl();
290 	}
291 
292 	public String getRemoteDeviceFriendlyName(long address) throws IOException {
293 		// TODO Properly if possible
294 		return null;
295 	}
296 
297 	// --- Service search
298 
299 	public int searchServices(int[] attrSet, UUID[] uuidSet, RemoteDevice device, DiscoveryListener listener)
300 			throws BluetoothStateException {
301 		return SearchServicesThread.startSearchServices(this, this, attrSet, uuidSet, device, listener);
302 	}
303 
304 	public boolean cancelServiceSearch(int transID) {
305 		return false;
306 	}
307 
308 	private native int runSearchServicesImpl(SearchServicesThread startedNotify, DiscoveryListener listener,
309 			byte[] uuidValue, long address, RemoteDevice device) throws BluetoothStateException;
310 
311 	public int runSearchServices(SearchServicesThread startedNotify, int[] attrSet, UUID[] uuidSet,
312 			RemoteDevice device, DiscoveryListener listener) throws BluetoothStateException {
313 		startedNotify.searchServicesStartedCallback();
314 		UUID uuid = null;
315 		if ((uuidSet != null) && (uuidSet.length > 0)) {
316 			uuid = uuidSet[uuidSet.length - 1];
317 		}
318 		return runSearchServicesImpl(startedNotify, listener, Utils.UUIDToByteArray(uuid), RemoteDeviceHelper
319 				.getAddress(device), device);
320 	}
321 
322 	/*
323 	 * This is all we have under the BlueSoleil. struct SPPEX_SERVICE_INFO { DWORD dwSize; DWORD dwSDAPRecordHanlde;
324 	 * UUID serviceClassUuid128; CHAR szServiceName[MAX_SERVICE_NAME_LENGTH]; UCHAR ucServiceChannel; }
325 	 */
326 
327 	public void servicesFoundCallback(SearchServicesThread startedNotify, DiscoveryListener listener,
328 			RemoteDevice device, String serviceName, byte[] uuidValue, int channel, long recordHanlde) {
329 
330 		ServiceRecordImpl record = new ServiceRecordImpl(this, device, 0);
331 
332 		UUID uuid = new UUID(Utils.UUIDByteArrayToString(uuidValue), false);
333 
334 		record.populateRFCOMMAttributes(recordHanlde, channel, uuid, serviceName, BluetoothConsts.obexUUIDs
335 				.contains(uuid));
336 		DebugLog.debug("servicesFoundCallback", record);
337 
338 		RemoteDevice listedDevice = RemoteDeviceHelper.createRemoteDevice(this, device);
339 		RemoteDeviceHelper.setStackAttributes(this, listedDevice, "RFCOMM_channel" + channel, uuid);
340 
341 		ServiceRecord[] records = new ServiceRecordImpl[1];
342 		records[0] = record;
343 		listener.servicesDiscovered(startedNotify.getTransID(), records);
344 	}
345 
346 	public boolean populateServicesRecordAttributeValues(ServiceRecordImpl serviceRecord, int[] attrIDs)
347 			throws IOException {
348 		return false;
349 	}
350 
351 	// --- Client RFCOMM connections
352 
353 	private native long connectionRfOpenImpl(long address, byte[] uuidValue) throws IOException;
354 
355 	public long connectionRfOpenClientConnection(BluetoothConnectionParams params) throws IOException {
356 		if (params.authenticate || params.encrypt) {
357 			throw new IOException("authenticate not supported on BlueSoleil");
358 		}
359 		RemoteDevice listedDevice = RemoteDeviceHelper.getCashedDevice(this, params.address);
360 		if (listedDevice == null) {
361 			throw new IOException("Device not discovered");
362 		}
363 		UUID uuid = (UUID) RemoteDeviceHelper.getStackAttributes(this, listedDevice, "RFCOMM_channel" + params.channel);
364 		if (uuid == null) {
365 			throw new IOException("Device service not discovered");
366 		}
367 		DebugLog.debug("Connect to service UUID", uuid);
368 		return connectionRfOpenImpl(params.address, Utils.UUIDToByteArray(uuid));
369 	}
370 
371 	public native void connectionRfCloseClientConnection(long handle) throws IOException;
372 
373 	private native long rfServerOpenImpl(byte[] uuidValue, String name, boolean authenticate, boolean encrypt)
374 			throws IOException;
375 
376 	private native int rfServerSCN(long handle) throws IOException;
377 
378 	public long rfServerOpen(BluetoothConnectionNotifierParams params, ServiceRecordImpl serviceRecord)
379 			throws IOException {
380 		if (params.authenticate || params.encrypt) {
381 			throw new IOException("authenticate not supported on BlueSoleil");
382 		}
383 		byte[] uuidValue = Utils.UUIDToByteArray(params.uuid);
384 		long handle = rfServerOpenImpl(uuidValue, params.name, params.authenticate, params.encrypt);
385 		int channel = rfServerSCN(handle);
386 		DebugLog.debug("serverSCN", channel);
387 		int serviceRecordHandle = (int) handle;
388 
389 		serviceRecord.populateRFCOMMAttributes(serviceRecordHandle, channel, params.uuid, params.name, false);
390 
391 		return handle;
392 	}
393 
394 	public void rfServerUpdateServiceRecord(long handle, ServiceRecordImpl serviceRecord, boolean acceptAndOpen)
395 			throws ServiceRegistrationException {
396 		if (!acceptAndOpen) {
397 			throw new ServiceRegistrationException("Not Supported on " + getStackID());
398 		}
399 	}
400 
401 	public native long rfServerAcceptAndOpenRfServerConnection(long handle) throws IOException;
402 
403 	public void connectionRfCloseServerConnection(long handle) throws IOException {
404 		connectionRfCloseClientConnection(handle);
405 	}
406 
407 	public native void rfServerClose(long handle, ServiceRecordImpl serviceRecord) throws IOException;
408 
409 	public native long getConnectionRfRemoteAddress(long handle) throws IOException;
410 
411 	public native int connectionRfRead(long handle) throws IOException;
412 
413 	public native int connectionRfRead(long handle, byte[] b, int off, int len) throws IOException;
414 
415 	public native int connectionRfReadAvailable(long handle) throws IOException;
416 
417 	public native void connectionRfWrite(long handle, int b) throws IOException;
418 
419 	public native void connectionRfWrite(long handle, byte[] b, int off, int len) throws IOException;
420 
421 	public native void connectionRfFlush(long handle) throws IOException;
422 
423 	public int rfGetSecurityOpt(long handle, int expected) throws IOException {
424 		return ServiceRecord.NOAUTHENTICATE_NOENCRYPT;
425 	}
426 
427 	/*
428 	 * (non-Javadoc)
429 	 * 
430 	 * @see com.intel.bluetooth.BluetoothStack#l2Encrypt(long,long,boolean)
431 	 */
432 	public boolean rfEncrypt(long address, long handle, boolean on) throws IOException {
433 		return false;
434 	}
435 
436 	// ---------------------- Client and Server L2CAP connections
437 
438 	/*
439 	 * (non-Javadoc)
440 	 * 
441 	 * @see com.intel.bluetooth.BluetoothStack#l2OpenClientConnection(com.intel.bluetooth .BluetoothConnectionParams,
442 	 * int, int)
443 	 */
444 	public long l2OpenClientConnection(BluetoothConnectionParams params, int receiveMTU, int transmitMTU)
445 			throws IOException {
446 		throw new NotSupportedIOException(getStackID());
447 	}
448 
449 	/*
450 	 * (non-Javadoc)
451 	 * 
452 	 * @see com.intel.bluetooth.BluetoothStack#l2CloseClientConnection(long)
453 	 */
454 	public void l2CloseClientConnection(long handle) throws IOException {
455 		throw new NotSupportedIOException(getStackID());
456 	}
457 
458 	/*
459 	 * (non-Javadoc)
460 	 * 
461 	 * @seecom.intel.bluetooth.BluetoothStack#l2ServerOpen(com.intel.bluetooth. BluetoothConnectionNotifierParams, int,
462 	 * int, com.intel.bluetooth.ServiceRecordImpl)
463 	 */
464 	public long l2ServerOpen(BluetoothConnectionNotifierParams params, int receiveMTU, int transmitMTU,
465 			ServiceRecordImpl serviceRecord) throws IOException {
466 		throw new NotSupportedIOException(getStackID());
467 	}
468 
469 	/*
470 	 * (non-Javadoc)
471 	 * 
472 	 * @see com.intel.bluetooth.BluetoothStack#l2ServerUpdateServiceRecord(long, com.intel.bluetooth.ServiceRecordImpl,
473 	 * boolean)
474 	 */
475 	public void l2ServerUpdateServiceRecord(long handle, ServiceRecordImpl serviceRecord, boolean acceptAndOpen)
476 			throws ServiceRegistrationException {
477 		throw new ServiceRegistrationException("Not Supported on" + getStackID());
478 	}
479 
480 	/*
481 	 * (non-Javadoc)
482 	 * 
483 	 * @see com.intel.bluetooth.BluetoothStack#l2ServerAcceptAndOpenServerConnection (long)
484 	 */
485 	public long l2ServerAcceptAndOpenServerConnection(long handle) throws IOException {
486 		throw new NotSupportedIOException(getStackID());
487 	}
488 
489 	/*
490 	 * (non-Javadoc)
491 	 * 
492 	 * @see com.intel.bluetooth.BluetoothStack#l2CloseServerConnection(long)
493 	 */
494 	public void l2CloseServerConnection(long handle) throws IOException {
495 		throw new NotSupportedIOException(getStackID());
496 	}
497 
498 	/*
499 	 * (non-Javadoc)
500 	 * 
501 	 * @see com.intel.bluetooth.BluetoothStack#l2ServerClose(long, com.intel.bluetooth.ServiceRecordImpl)
502 	 */
503 	public void l2ServerClose(long handle, ServiceRecordImpl serviceRecord) throws IOException {
504 		throw new NotSupportedIOException(getStackID());
505 	}
506 
507 	/*
508 	 * (non-Javadoc)
509 	 * 
510 	 * @see com.intel.bluetooth.BluetoothStack#l2GetSecurityOpt(long, int)
511 	 */
512 	public int l2GetSecurityOpt(long handle, int expected) throws IOException {
513 		throw new NotSupportedIOException(getStackID());
514 	}
515 
516 	/*
517 	 * (non-Javadoc)
518 	 * 
519 	 * @see com.intel.bluetooth.BluetoothStack#l2Ready(long)
520 	 */
521 	public boolean l2Ready(long handle) throws IOException {
522 		throw new NotSupportedIOException(getStackID());
523 	}
524 
525 	/*
526 	 * (non-Javadoc)
527 	 * 
528 	 * @see com.intel.bluetooth.BluetoothStack#l2receive(long, byte[])
529 	 */
530 	public int l2Receive(long handle, byte[] inBuf) throws IOException {
531 		throw new NotSupportedIOException(getStackID());
532 	}
533 
534 	/*
535 	 * (non-Javadoc)
536 	 * 
537 	 * @see com.intel.bluetooth.BluetoothStack#l2send(long, byte[])
538 	 */
539 	public void l2Send(long handle, byte[] data) throws IOException {
540 		throw new NotSupportedIOException(getStackID());
541 	}
542 
543 	/*
544 	 * (non-Javadoc)
545 	 * 
546 	 * @see com.intel.bluetooth.BluetoothStack#l2GetReceiveMTU(long)
547 	 */
548 	public int l2GetReceiveMTU(long handle) throws IOException {
549 		throw new NotSupportedIOException(getStackID());
550 	}
551 
552 	/*
553 	 * (non-Javadoc)
554 	 * 
555 	 * @see com.intel.bluetooth.BluetoothStack#l2GetTransmitMTU(long)
556 	 */
557 	public int l2GetTransmitMTU(long handle) throws IOException {
558 		throw new NotSupportedIOException(getStackID());
559 	}
560 
561 	/*
562 	 * (non-Javadoc)
563 	 * 
564 	 * @see com.intel.bluetooth.BluetoothStack#l2RemoteAddress(long)
565 	 */
566 	public long l2RemoteAddress(long handle) throws IOException {
567 		throw new NotSupportedIOException(getStackID());
568 	}
569 
570 	/*
571 	 * (non-Javadoc)
572 	 * 
573 	 * @see com.intel.bluetooth.BluetoothStack#l2Encrypt(long,long,boolean)
574 	 */
575 	public boolean l2Encrypt(long address, long handle, boolean on) throws IOException {
576 		throw new NotSupportedIOException(getStackID());
577 	}
578 
579 }