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   *  @author vlads
23   *  @version $Id: RemoteDeviceHelper.java 2476 2008-12-01 17:41:59Z skarzhevskyy $
24   */
25  package com.intel.bluetooth;
26  
27  import java.io.IOException;
28  import java.util.Enumeration;
29  import java.util.Hashtable;
30  import java.util.Vector;
31  
32  import javax.bluetooth.BluetoothStateException;
33  import javax.bluetooth.DiscoveryAgent;
34  import javax.bluetooth.RemoteDevice;
35  import javax.bluetooth.ServiceRecord;
36  import javax.microedition.io.Connection;
37  
38  import com.intel.bluetooth.WeakVectorFactory.WeakVector;
39  
40  /**
41   * Implementation of RemoteDevice.
42   *
43   * Instance of RemoteDevice can be created by User. BlueCove should use only RemoteDeviceHelper class to create
44   * RemoteDevice instances.
45   *
46   * <p>
47   * <b><u>Your application should not use this class directly.</u></b>
48   *
49   * The exceptions are authenticate(RemoteDevice device, String passkey) and removeAuthentication(RemoteDevice device).
50   */
51  public abstract class RemoteDeviceHelper {
52  
53  	private static class RemoteDeviceWithExtendedInfo extends RemoteDevice {
54  
55  		String name;
56  
57  		long addressLong;
58  
59  		BluetoothStack bluetoothStack;
60  
61  		private Hashtable stackAttributes;
62  
63  		private boolean paired;
64  
65  		/**
66  		 * Connections can be discarded by the garbage collector.
67  		 */
68  		private WeakVector connections;
69  
70  		private RemoteDeviceWithExtendedInfo(BluetoothStack bluetoothStack, long address, String name) {
71  			super(RemoteDeviceHelper.getBluetoothAddress(address));
72  			this.bluetoothStack = bluetoothStack;
73  			this.name = name;
74  			this.addressLong = address;
75  		}
76  
77  		private void addConnection(Object connection) {
78  			synchronized (this) {
79  				if (connections == null) {
80  					connections = WeakVectorFactory.createWeakVector();
81  				}
82  			}
83  			synchronized (connections) {
84  				connections.addElement(connection);
85  				DebugLog.debug("connection open, open now", connections.size());
86  			}
87  		}
88  
89  		private void removeConnection(Object connection) {
90  			if (connections == null) {
91  				return;
92  			}
93  			synchronized (connections) {
94  				connections.removeElement(connection);
95  				DebugLog.debug("connection closed, open now", connections.size());
96  			}
97  		}
98  
99  		void shutdownConnections() {
100 			if (!hasConnections()) {
101 				return;
102 			}
103 			Vector c2shutdown = new Vector();
104 			synchronized (connections) {
105 				c2shutdown = Utils.clone(connections.elements());
106 			}
107 			for (Enumeration en = c2shutdown.elements(); en.hasMoreElements();) {
108 				BluetoothConnectionAccess c = (BluetoothConnectionAccess) en.nextElement();
109 				try {
110 					c.shutdown();
111 				} catch (IOException e) {
112 					DebugLog.debug("connection shutdown", e);
113 				}
114 			}
115 			synchronized (connections) {
116 				connections.removeAllElements();
117 			}
118 		}
119 
120 		private void setStackAttributes(Object key, Object value) {
121 			if (stackAttributes == null) {
122 				stackAttributes = new Hashtable();
123 			}
124 			if (value == null) {
125 				stackAttributes.remove(key);
126 			} else {
127 				stackAttributes.put(key, value);
128 			}
129 		}
130 
131 		private Object getStackAttributes(Object key) {
132 			if (stackAttributes == null) {
133 				return null;
134 			}
135 			return stackAttributes.get(key);
136 		}
137 
138 		public String toString() {
139 			return super.getBluetoothAddress();
140 		}
141 
142 		int connectionsCount() {
143 			if (connections == null) {
144 				return 0;
145 			}
146 			return connections.size();
147 		}
148 
149 		boolean hasConnections() {
150 			return (connectionsCount() != 0);
151 		}
152 
153 		/**
154 		 * @see javax.bluetooth.RemoteDevice#authenticate()
155 		 */
156 		public boolean authenticate() throws IOException {
157 			if (!hasConnections()) {
158 				throw new IOException("No open connections to this RemoteDevice");
159 			}
160 			if (this.isAuthenticated()) {
161 				// has previously been authenticated
162 				return true;
163 			}
164 			boolean authenticated = bluetoothStack.authenticateRemoteDevice(addressLong);
165 			paired = authenticated;
166 			if (authenticated) {
167 				updateConnectionMarkAuthenticated();
168 			}
169 			return authenticated;
170 		}
171 
172 		/**
173 		 * @see com.intel.bluetooth.RemoteDeviceHelper#authenticateRemoteDevice(RemoteDevice, java.lang.String)
174 		 */
175 		boolean authenticate(String passkey) throws IOException {
176 			boolean authenticated = bluetoothStack.authenticateRemoteDevice(addressLong, passkey);
177 			paired = authenticated;
178 			if (authenticated) {
179 				updateConnectionMarkAuthenticated();
180 			}
181 			return authenticated;
182 		}
183 
184 		void removeAuthentication() throws IOException {
185 			bluetoothStack.removeAuthenticationWithRemoteDevice(addressLong);
186 			paired = false;
187 		}
188 
189 		private void updateConnectionMarkAuthenticated() {
190 			if (connections == null) {
191 				return;
192 			}
193 			synchronized (connections) {
194 				for (Enumeration en = connections.elements(); en.hasMoreElements();) {
195 					BluetoothConnectionAccess c = (BluetoothConnectionAccess) en.nextElement();
196 					c.markAuthenticated();
197 				}
198 			}
199 		}
200 
201 		/**
202 		 * Determines if this RemoteDevice should be allowed to continue to access the local service provided by the
203 		 * Connection.
204 		 *
205 		 * @see javax.bluetooth.RemoteDevice#authorize(javax.microedition.io.Connection)
206 		 */
207 		public boolean authorize(Connection conn) throws IOException {
208 			if (!(conn instanceof BluetoothConnectionAccess)) {
209 				throw new IllegalArgumentException("Connection is not a Bluetooth connection");
210 			}
211 			if (((BluetoothConnectionAccess) conn).isClosed()) {
212 				throw new IOException("Connection is already closed");
213 			}
214 			if (!(conn instanceof BluetoothServerConnection)) {
215 				throw new IllegalArgumentException("Connection is not an incomming Bluetooth connection");
216 			}
217 			return isTrustedDevice() || isAuthenticated();
218 		}
219 
220 		/**
221 		 *
222 		 * @see javax.bluetooth.RemoteDevice#isAuthorized(javax.microedition.io.Connection)
223 		 */
224 		public boolean isAuthorized(Connection conn) throws IOException {
225 			if (!(conn instanceof BluetoothConnectionAccess)) {
226 				throw new IllegalArgumentException("Connection is not a Bluetooth connection");
227 			}
228 			if (((BluetoothConnectionAccess) conn).isClosed()) {
229 				throw new IOException("Connection is already closed");
230 			}
231 			if (!(conn instanceof BluetoothServerConnection)) {
232 				throw new IllegalArgumentException("Connection is not an incomming Bluetooth connection");
233 			}
234 			return isTrustedDevice();
235 		}
236 
237 		/**
238 		 * Attempts to turn encryption on or off for an existing connection.
239 		 *
240 		 * @see javax.bluetooth.RemoteDevice#encrypt(javax.microedition.io.Connection, boolean)
241 		 */
242 		public boolean encrypt(Connection conn, boolean on) throws IOException {
243 			if (!(conn instanceof BluetoothConnectionAccess)) {
244 				throw new IllegalArgumentException("Connection is not a Bluetooth connection");
245 			}
246 			if (((BluetoothConnectionAccess) conn).getRemoteAddress() != this.addressLong) {
247 				throw new IllegalArgumentException("Connection is not to this device");
248 			}
249 			if ((((BluetoothConnectionAccess) conn).getSecurityOpt() == ServiceRecord.AUTHENTICATE_ENCRYPT) == on) {
250 				return true;
251 			}
252 			return ((BluetoothConnectionAccess) conn).encrypt(this.addressLong, on);
253 		}
254 
255 		/*
256 		 * (non-Javadoc)
257 		 *
258 		 * @see javax.bluetooth.RemoteDevice#isAuthenticated()
259 		 */
260 		public boolean isAuthenticated() {
261 			if (!hasConnections()) {
262 				DebugLog.debug("no connections, Authenticated = false");
263 				return false;
264 			}
265 			Boolean authenticated = bluetoothStack.isRemoteDeviceAuthenticated(addressLong);
266 			if (authenticated != null) {
267 				return authenticated.booleanValue();
268 			}
269 			synchronized (connections) {
270 				// Find first authenticated connection
271 				for (Enumeration en = connections.elements(); en.hasMoreElements();) {
272 					BluetoothConnectionAccess c = (BluetoothConnectionAccess) en.nextElement();
273 					if (c.getSecurityOpt() != ServiceRecord.NOAUTHENTICATE_NOENCRYPT) {
274 						return true;
275 					}
276 				}
277 			}
278 			return false;
279 		}
280 
281 		/*
282 		 * (non-Javadoc)
283 		 *
284 		 * @see javax.bluetooth.RemoteDevice#isEncrypted()
285 		 */
286 		public boolean isEncrypted() {
287 			if (!hasConnections()) {
288 				return false;
289 			}
290 			synchronized (connections) {
291 				// Find first encrypted connection
292 				for (Enumeration en = connections.elements(); en.hasMoreElements();) {
293 					BluetoothConnectionAccess c = (BluetoothConnectionAccess) en.nextElement();
294 					if (c.getSecurityOpt() == ServiceRecord.AUTHENTICATE_ENCRYPT) {
295 						return true;
296 					}
297 				}
298 			}
299 			return false;
300 		}
301 
302 		/*
303 		 * (non-Javadoc)
304 		 *
305 		 * @see javax.bluetooth.RemoteDevice#isTrustedDevice()
306 		 */
307 		public boolean isTrustedDevice() {
308 			Boolean trusted = bluetoothStack.isRemoteDeviceTrusted(addressLong);
309 			if (trusted == null) {
310 				return paired;
311 			} else {
312 				return trusted.booleanValue();
313 			}
314 		}
315 	}
316 
317 	private static Hashtable stackDevicesCashed = new Hashtable();
318 
319 	private RemoteDeviceHelper() {
320 
321 	}
322 
323 	private static synchronized Hashtable devicesCashed(BluetoothStack bluetoothStack) {
324 		Hashtable devicesCashed = (Hashtable) stackDevicesCashed.get(bluetoothStack);
325 		if (devicesCashed == null) {
326 			devicesCashed = new Hashtable();
327 			stackDevicesCashed.put(bluetoothStack, devicesCashed);
328 		}
329 		return devicesCashed;
330 	}
331 
332 	private static RemoteDeviceWithExtendedInfo getCashedDeviceWithExtendedInfo(BluetoothStack bluetoothStack,
333 			long address) {
334 		Object key = new Long(address);
335 		return (RemoteDeviceWithExtendedInfo) devicesCashed(bluetoothStack).get(key);
336 	}
337 
338 	static RemoteDevice getCashedDevice(BluetoothStack bluetoothStack, long address) {
339 		return getCashedDeviceWithExtendedInfo(bluetoothStack, address);
340 	}
341 
342 	static RemoteDevice createRemoteDevice(BluetoothStack bluetoothStack, long address, String name, boolean paired) {
343 		RemoteDeviceWithExtendedInfo dev = getCashedDeviceWithExtendedInfo(bluetoothStack, address);
344 		if (dev == null) {
345 			Object saveID = BlueCoveImpl.getCurrentThreadBluetoothStackID();
346 			try {
347 				BlueCoveImpl.setThreadBluetoothStack(bluetoothStack);
348 				dev = new RemoteDeviceWithExtendedInfo(bluetoothStack, address, name);
349 			} finally {
350 				if (saveID != null) {
351 					BlueCoveImpl.setThreadBluetoothStackID(saveID);
352 				}
353 			}
354 			devicesCashed(bluetoothStack).put(new Long(address), dev);
355 			DebugLog.debug0x("new devicesCashed", address);
356 		} else if (!Utils.isStringSet(dev.name)) {
357 			// New name found
358 			dev.name = name;
359 		} else if (Utils.isStringSet(name)) {
360 			// Update name if changed
361 			dev.name = name;
362 		}
363 		if (paired) {
364 			dev.paired = paired;
365 		}
366 		return dev;
367 	}
368 
369 	private static BluetoothStack getBluetoothStack() throws RuntimeException {
370 		try {
371 			return BlueCoveImpl.instance().getBluetoothStack();
372 		} catch (BluetoothStateException e) {
373 			throw (RuntimeException) UtilsJavaSE.initCause(new RuntimeException("Can't initialize bluetooth support"),
374 					e);
375 		}
376 	}
377 
378 	private static RemoteDeviceWithExtendedInfo remoteDeviceImpl(RemoteDevice device) {
379 		return (RemoteDeviceWithExtendedInfo) createRemoteDevice(null, device);
380 	}
381 
382 	static RemoteDevice createRemoteDevice(BluetoothStack bluetoothStack, RemoteDevice device) throws RuntimeException {
383 		if (device instanceof RemoteDeviceWithExtendedInfo) {
384 			return device;
385 		} else {
386 			if (bluetoothStack == null) {
387 				bluetoothStack = getBluetoothStack();
388 			}
389 			return createRemoteDevice(bluetoothStack, getAddress(device), null, false);
390 		}
391 	}
392 
393 	public static String getFriendlyName(RemoteDevice device, long address, boolean alwaysAsk) throws IOException {
394 		String name = null;
395 		if (!(device instanceof RemoteDeviceWithExtendedInfo)) {
396 			device = createRemoteDevice(null, device);
397 		}
398 		name = ((RemoteDeviceWithExtendedInfo) device).name;
399 		if (alwaysAsk || (!Utils.isStringSet(name))) {
400 			name = ((RemoteDeviceWithExtendedInfo) device).bluetoothStack.getRemoteDeviceFriendlyName(address);
401 			if (Utils.isStringSet(name)) {
402 				((RemoteDeviceWithExtendedInfo) device).name = name;
403 			} else {
404 				throw new IOException("Can't query remote device");
405 			}
406 		}
407 		return name;
408 	}
409 
410 	/**
411 	 * @see javax.bluetooth.RemoteDevice#getRemoteDevice(Connection)
412 	 */
413 	public static RemoteDevice getRemoteDevice(Connection conn) throws IOException {
414 		if (!(conn instanceof BluetoothConnectionAccess)) {
415 			throw new IllegalArgumentException("Not a Bluetooth connection " + conn.getClass().getName());
416 		}
417 		return createRemoteDevice(((BluetoothConnectionAccess) conn).getBluetoothStack(),
418 				((BluetoothConnectionAccess) conn).getRemoteAddress(), null, false);
419 	}
420 
421 	/**
422 	 * (non-Javadoc)
423 	 *
424 	 * @see javax.bluetooth.DiscoveryAgent#retrieveDevices(int)
425 	 */
426 	public static RemoteDevice[] retrieveDevices(BluetoothStack bluetoothStack, int option) {
427 		if ((option != DiscoveryAgent.PREKNOWN) && (option != DiscoveryAgent.CACHED)) {
428 			throw new IllegalArgumentException("invalid option");
429 		}
430 		RemoteDevice[] impl = bluetoothStack.retrieveDevices(option);
431 		if (impl != null) {
432 			if (impl.length == 0) {
433 				// Spec: null if no devices meet the criteria
434 				return null;
435 			} else {
436 				return impl;
437 			}
438 		}
439 
440 		Hashtable devicesCashed = devicesCashed(bluetoothStack);
441 		switch (option) {
442 		case DiscoveryAgent.PREKNOWN:
443 			if (devicesCashed.size() == 0) {
444 				// Spec: null if no devices meet the criteria
445 				return null;
446 			}
447 			Vector devicesPaired = new Vector();
448 			for (Enumeration en = devicesCashed.elements(); en.hasMoreElements();) {
449 				RemoteDeviceWithExtendedInfo d = (RemoteDeviceWithExtendedInfo) en.nextElement();
450 				if (d.isTrustedDevice()) {
451 					devicesPaired.addElement(d);
452 				}
453 			}
454 			if (devicesPaired.size() == 0) {
455 				// Spec: null if no devices meet the criteria
456 				return null;
457 			}
458 			return remoteDeviceListToArray(devicesPaired);
459 		case DiscoveryAgent.CACHED:
460 			if (devicesCashed.size() == 0) {
461 				// Spec: null if no devices meet the criteria
462 				return null;
463 			}
464 			RemoteDevice[] devices = new RemoteDevice[devicesCashed.size()];
465 			int k = 0;
466 			for (Enumeration en = devicesCashed.elements(); en.hasMoreElements();) {
467 				devices[k++] = (RemoteDevice) en.nextElement();
468 			}
469 			return devices;
470 		default:
471 			throw new IllegalArgumentException("invalid option");
472 		}
473 	}
474 
475 	static RemoteDevice[] remoteDeviceListToArray(Vector devices) {
476 		RemoteDevice[] devicesArray = new RemoteDevice[devices.size()];
477 		int i = 0;
478 		for (Enumeration en = devices.elements(); en.hasMoreElements();) {
479 			devicesArray[i++] = (RemoteDevice) en.nextElement();
480 		}
481 		return devicesArray;
482 	}
483 
484 	/**
485 	 * Count total number of open connections to all devices.
486 	 *
487 	 * @return number of connections
488 	 */
489 	public static int openConnections() {
490 		int c = 0;
491 		Hashtable devicesCashed = devicesCashed(getBluetoothStack());
492 		synchronized (devicesCashed) {
493 			for (Enumeration en = devicesCashed.elements(); en.hasMoreElements();) {
494 				c += ((RemoteDeviceWithExtendedInfo) en.nextElement()).connectionsCount();
495 			}
496 		}
497 		return c;
498 	}
499 
500 	/**
501 	 * Count number of open connections to or from specific device.
502 	 *
503 	 * @return number of connections
504 	 */
505 	public static int openConnections(long address) {
506 		RemoteDeviceWithExtendedInfo dev = getCashedDeviceWithExtendedInfo(getBluetoothStack(), address);
507 		if (dev == null) {
508 			return 0;
509 		}
510 		return dev.connectionsCount();
511 	}
512 
513 	/**
514 	 * Count number of device that have open connections to or from them.
515 	 *
516 	 * @return number of connections
517 	 */
518 	public static int connectedDevices() {
519 		int c = 0;
520 		Hashtable devicesCashed = devicesCashed(getBluetoothStack());
521 		synchronized (devicesCashed) {
522 			for (Enumeration en = devicesCashed.elements(); en.hasMoreElements();) {
523 				if (((RemoteDeviceWithExtendedInfo) en.nextElement()).hasConnections()) {
524 					c++;
525 				}
526 			}
527 		}
528 		return c;
529 	}
530 
531 	static void shutdownConnections(BluetoothStack bluetoothStack) {
532 		Hashtable devicesCashed = devicesCashed(bluetoothStack);
533 		synchronized (devicesCashed) {
534 			for (Enumeration en = devicesCashed.elements(); en.hasMoreElements();) {
535 				((RemoteDeviceWithExtendedInfo) en.nextElement()).shutdownConnections();
536 			}
537 		}
538 	}
539 
540 	public static String formatBluetoothAddress(String address) {
541 		String s = address.toUpperCase();
542 		return "000000000000".substring(s.length()) + s;
543 	}
544 
545 	public static String getBluetoothAddress(long address) {
546 		return formatBluetoothAddress(Utils.toHexString(address));
547 	}
548 
549 	public static long getAddress(String bluetoothAddress) {
550 		if (bluetoothAddress.indexOf('-') != -1) {
551 			throw new IllegalArgumentException("Illegal bluetoothAddress {" + bluetoothAddress + "}");
552 		}
553 		try {
554 			return Long.parseLong(bluetoothAddress, 16);
555 		} catch (NumberFormatException e) {
556 			throw new IllegalArgumentException("Illegal bluetoothAddress {" + bluetoothAddress + "}; should be hex number");
557 		}
558 	}
559 
560 	static long getAddress(RemoteDevice device) {
561 		if (device instanceof RemoteDeviceWithExtendedInfo) {
562 			return ((RemoteDeviceWithExtendedInfo) device).addressLong;
563 		} else {
564 			return getAddress(device.getBluetoothAddress());
565 		}
566 	}
567 
568 	static void setStackAttributes(BluetoothStack bluetoothStack, RemoteDevice device, Object key, Object value) {
569 		RemoteDeviceWithExtendedInfo devInfo = (RemoteDeviceWithExtendedInfo) createRemoteDevice(bluetoothStack, device);
570 		devInfo.setStackAttributes(key, value);
571 	}
572 
573 	static Object getStackAttributes(BluetoothStack bluetoothStack, RemoteDevice device, Object key) {
574 		RemoteDeviceWithExtendedInfo devInfo = null;
575 		if (device instanceof RemoteDeviceWithExtendedInfo) {
576 			devInfo = (RemoteDeviceWithExtendedInfo) device;
577 		} else {
578 			devInfo = getCashedDeviceWithExtendedInfo(bluetoothStack, getAddress(device));
579 		}
580 
581 		if (devInfo != null) {
582 			return devInfo.getStackAttributes(key);
583 		} else {
584 			return null;
585 		}
586 	}
587 
588 	static void connected(BluetoothConnectionAccess connection) throws IOException {
589 		RemoteDeviceWithExtendedInfo device = (RemoteDeviceWithExtendedInfo) getRemoteDevice((Connection) connection);
590 		connection.setRemoteDevice(device);
591 		device.addConnection(connection);
592 	}
593 
594 	static void disconnected(BluetoothConnectionAccess connection) {
595 		RemoteDevice d = connection.getRemoteDevice();
596 		if (d != null) {
597 			((RemoteDeviceWithExtendedInfo) d).removeConnection(connection);
598 			connection.setRemoteDevice(null);
599 		}
600 	}
601 
602 	/**
603 	 * Attempts to authenticate RemoteDevice. Return <code>false</code> if the stack does not support authentication.
604 	 *
605 	 * @see javax.bluetooth.RemoteDevice#authenticate()
606 	 */
607 	public static boolean authenticate(RemoteDevice device) throws IOException {
608 		return remoteDeviceImpl(device).authenticate();
609 	}
610 
611 	/**
612 	 *
613 	 * Sends an authentication request to a remote Bluetooth device. Non JSR-82, Return <code>false</code> if the stack
614 	 * does not support authentication.
615 	 * <p>
616 	 * <b>PUBLIC JSR-82 extension</b>
617 	 *
618 	 * @param device
619 	 *            Remote Device
620 	 * @param passkey
621 	 *            A Personal Identification Number (PIN) to be used for device authentication.
622 	 * @return <code>true</code> if authentication is successful; otherwise <code>false</code>
623 	 * @throws IOException
624 	 *             if there are error during authentication.
625 	 */
626 	public static boolean authenticate(RemoteDevice device, String passkey) throws IOException {
627 		return remoteDeviceImpl(device).authenticate(passkey);
628 	}
629 
630 	/**
631 	 *
632 	 * Removes authentication between local and remote bluetooth devices. Non JSR-82.
633 	 * <p>
634 	 * <b>PUBLIC JSR-82 extension</b>
635 	 *
636 	 * @param device
637 	 *            Remote Device
638 	 *
639 	 * @throws IOException
640 	 *             if there are errors or not implemented.
641 	 */
642 	public static void removeAuthentication(RemoteDevice device) throws IOException {
643 		remoteDeviceImpl(device).removeAuthentication();
644 	}
645 
646 	/**
647 	 * Determines if this RemoteDevice should be allowed to continue to access the local service provided by the
648 	 * Connection.
649 	 *
650 	 * @see javax.bluetooth.RemoteDevice#authorize(javax.microedition.io.Connection)
651 	 */
652 	public static boolean authorize(RemoteDevice device, Connection conn) throws IOException {
653 		return remoteDeviceImpl(device).authorize(conn);
654 	}
655 
656 	/**
657 	 * Attempts to turn encryption on or off for an existing connection.
658 	 *
659 	 * @see javax.bluetooth.RemoteDevice#encrypt(javax.microedition.io.Connection, boolean)
660 	 */
661 	public static boolean encrypt(RemoteDevice device, Connection conn, boolean on) throws IOException {
662 		return remoteDeviceImpl(device).encrypt(conn, on);
663 	}
664 
665 	/**
666 	 * Determines if this <code>RemoteDevice</code> has been authenticated.
667 	 * <P>
668 	 * A device may have been authenticated by this application or another application. Authentication applies to an ACL
669 	 * link between devices and not on a specific L2CAP, RFCOMM, or OBEX connection. Therefore, if
670 	 * <code>authenticate()</code> is performed when an L2CAP connection is made to device A, then
671 	 * <code>isAuthenticated()</code> may return <code>true</code> when tested as part of making an RFCOMM connection to
672 	 * device A.
673 	 *
674 	 * @return <code>true</code> if this <code>RemoteDevice</code> has previously been authenticated; <code>false</code>
675 	 *         if it has not been authenticated or there are no open connections between the local device and this
676 	 *         <code>RemoteDevice</code>
677 	 */
678 	public static boolean isAuthenticated(RemoteDevice device) {
679 		return remoteDeviceImpl(device).isAuthenticated();
680 	}
681 
682 	public static boolean isAuthorized(RemoteDevice device, Connection conn) throws IOException {
683 		return remoteDeviceImpl(device).isAuthorized(conn);
684 	}
685 
686 	/**
687 	 * Determines if data exchanges with this <code>RemoteDevice</code> are currently being encrypted.
688 	 * <P>
689 	 * Encryption may have been previously turned on by this or another application. Encryption applies to an ACL link
690 	 * between devices and not on a specific L2CAP, RFCOMM, or OBEX connection. Therefore, if <code>encrypt()</code> is
691 	 * performed with the <code>on</code> parameter set to <code>true</code> when an L2CAP connection is made to device
692 	 * A, then <code>isEncrypted()</code> may return <code>true</code> when tested as part of making an RFCOMM
693 	 * connection to device A.
694 	 *
695 	 * @return <code>true</code> if data exchanges with this <code>RemoteDevice</code> are being encrypted;
696 	 *         <code>false</code> if they are not being encrypted, or there are no open connections between the local
697 	 *         device and this <code>RemoteDevice</code>
698 	 */
699 	public static boolean isEncrypted(RemoteDevice device) {
700 		return remoteDeviceImpl(device).isEncrypted();
701 	}
702 
703 	public static boolean isTrustedDevice(RemoteDevice device) {
704 		return remoteDeviceImpl(device).isTrustedDevice();
705 	}
706 }