001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026: package com.sun.kvem.jsr082.bluetooth;
027:
028: import javax.bluetooth.*;
029: import java.io.IOException;
030: import java.util.Hashtable;
031: import com.sun.midp.jsr82emul.DeviceEmul;
032: import com.sun.midp.main.Configuration;
033: import java.util.Vector;
034:
035: /**
036: * Java-based Bluetooth Control Center.
037: */
038: public class JavaBCC extends BCC {
039:
040: /**
041: * Structure containing information on a remote device.
042: */
043: private class PicoNode {
044: /** Number of open connections. */
045: int connections;
046: /** Indicates whether the device has been authenticated. */
047: boolean authenticated;
048: /** Number of encrypted connections. */
049: int encrypted;
050: }
051:
052: /** Hashtable of PicoNodes. */
053: private Hashtable piconet = new Hashtable();
054:
055: /** Inquiry access code for the local device. */
056: private int accessCode = DiscoveryAgent.GIAC;
057:
058: /** Device class without service classes. */
059: private int deviceClassBase = 0x204; // 0x200 - phone (major class),
060: // 0x04 - cellular (minor class)
061:
062: /** Device class and service classes of the local device. */
063: private DeviceClass deviceClass;
064:
065: /** Identifies weither the Bluetooth device is on. */
066: private boolean isBluetoothEnabled = true;
067:
068: /** The friendly name for the device. */
069: private String friendlyName = "BT Emulation";
070:
071: /** Pass key for the device. */
072: private String passKey = "0000";
073:
074: /** Constructs an instance. */
075: protected JavaBCC() {
076: loadPropertyValues();
077: deviceClass = new DeviceClass(deviceClassBase);
078: }
079:
080: /**
081: * Enables Bluetooth radio and the Bluetooth protocol stack for use.
082: *
083: * @return <code>true</code> if the operation succeeded,
084: * <code>false</code> otherwise
085: */
086: public boolean enableBluetooth() {
087: isBluetoothEnabled = true;
088: return true;
089: }
090:
091: /**
092: * Queries the power state of the Bluetooth device.
093: *
094: * @return <code>true</code> is the Bluetooth device is on,
095: * <code>false</code> otherwise.
096: */
097: public boolean isBluetoothEnabled() {
098: return isBluetoothEnabled;
099: }
100:
101: /**
102: * Returns local Bluetooth address.
103: * @return local Bluetooth address
104: */
105: public String getBluetoothAddress() {
106: return com.sun.midp.jsr082.BluetoothUtils
107: .getAddressString(DeviceEmul.getLocalDeviceEmul()
108: .getAddress());
109: }
110:
111: /**
112: * Returns user-friendly name for the local device.
113: *
114: * @return User-friendly name for the local device, or
115: * <code>null</code> if the name could not be retrieved
116: */
117: public String getFriendlyName() {
118: return friendlyName;
119: }
120:
121: /**
122: * Retrieves the user-friendly name for specified remote device.
123: *
124: * @param address Bluetooth address of a remote device
125: * @return name of the remote device, or
126: * <code>null</code> if the name could not be retrieved
127: */
128: public String getFriendlyName(String address) {
129: return address;
130: }
131:
132: /**
133: * Checks if the local device is in connectable mode.
134: *
135: * @return <code>true</code> if the device is connectable,
136: * <code>false</code> otherwise
137: */
138: public boolean isConnectable() {
139: return true;
140: }
141:
142: // JAVADOC COMMENT ELIDED
143: public DeviceClass getDeviceClass() {
144: return deviceClass;
145: }
146:
147: // JAVADOC COMMENT ELIDED
148: public boolean setServiceClasses(int classes) {
149: deviceClass = new DeviceClass(deviceClassBase | classes);
150: DeviceEmul.getLocalDeviceEmul().updateDeviceClass(deviceClass);
151: return true;
152: }
153:
154: // JAVADOC COMMENT ELIDED
155: public int getAccessCode() {
156: return accessCode;
157: }
158:
159: // JAVADOC COMMENT ELIDED
160: public boolean setAccessCode(int accessCode) {
161: if (DeviceEmul.getLocalDeviceEmul().updateDiscoverable(
162: accessCode)) {
163: this .accessCode = accessCode;
164: return true;
165: }
166: return false;
167: }
168:
169: /**
170: * Checks if the local device has a bond with a remote device.
171: *
172: * @param address Bluetooth address of a remote device
173: * @return <code>true</code> if the two devices were paired,
174: * <code>false</code> otherwise
175: */
176: public boolean isPaired(String address) {
177: return true;
178: }
179:
180: /**
181: * Checks if a remote device was authenticated.
182: *
183: * @param address Bluetooth address of a remote device
184: * @return <code>true</code> if the device was authenticated,
185: * <code>false</code> otherwise
186: */
187: public boolean isAuthenticated(String address) {
188: return true;
189: }
190:
191: /**
192: * Checks if a remote device is trusted (authorized for all services).
193: *
194: * @param address Bluetooth address of a remote device
195: * @return <code>true</code> if the device is trusted,
196: * <code>false</code> otherwise
197: */
198: public boolean isTrusted(String address) {
199: return true;
200: }
201:
202: /**
203: * Checks if connections to a remote are encrypted.
204: *
205: * @param address Bluetooth address of a remote device
206: * @return <code>true</code> if connections to the device are encrypted,
207: * <code>false</code> otherwise
208: */
209: public boolean isEncrypted(String address) {
210: return true;
211: }
212:
213: /**
214: * Retrieves PIN code to use for pairing with a remote device. If the
215: * PIN code is not known, PIN entry dialog is displayed.
216: *
217: * @param address the Bluetooth address of the remote device
218: * @return string containing the PIN code
219: */
220: public String getPasskey(String address) {
221: return passKey;
222: }
223:
224: /**
225: * Initiates pairing with a remote device.
226: *
227: * @param address the Bluetooth address of the device with which to pair
228: * @param pin an array containing the PIN code
229: * @return <code>true</code> if the device was authenticated,
230: * <code>false</code> otherwise
231: */
232: public boolean bond(String address, String pin) {
233: return true;
234: }
235:
236: /**
237: * Authenticates remote device.
238: *
239: * @param address Bluetooth address of a remote device
240: * @return <code>true</code> if the device was authenticated,
241: * <code>false</code> otherwise
242: */
243: public boolean authenticate(String address) {
244: PicoNode pico = (PicoNode) piconet.get(address);
245: if (pico == null) {
246: return false;
247: }
248: pico.authenticated = true;
249: return true;
250: }
251:
252: /**
253: * Authorizes a Bluetooth connection.
254: *
255: * @param address the Bluetooth address of the remote device
256: * @param handle handle for the service record of the srvice the remote
257: * device is trying to access
258: * @return <code>true</code> if authorization succeeded,
259: * <code>false</code> otherwise
260: */
261: public boolean authorize(String address, int handle) {
262: return true;
263: }
264:
265: // JAVADOC COMMENT ELIDED
266: public boolean encrypt(String address, boolean enable) {
267: return false;
268: }
269:
270: /**
271: * Returns list of preknown devices in a Vector.
272: *
273: * @return Vector object containing preknown devices
274: */
275: public Vector getPreknownDevices() {
276: return null;
277: }
278:
279: /**
280: * Returns the number of connections to the remote device.
281: *
282: * @param address the Bluetooth address of the remote device
283: * @return number of connections established with the remote device
284: */
285: public int getConnectionCount(String address) {
286: PicoNode pico = (PicoNode) piconet.get(address);
287: return pico != null ? pico.connections : 0;
288: }
289:
290: /**
291: * Registers a new connection to a remote device.
292: *
293: * @param address the Bluetooth address of the remote device
294: */
295: public void addConnection(String address) {
296: PicoNode pico = (PicoNode) piconet.get(address);
297: if (pico == null) {
298: piconet.put(address, pico = new PicoNode());
299: }
300: pico.connections++;
301: }
302:
303: /**
304: * Unregisters an existing connection to a remote device.
305: *
306: * @param address the Bluetooth address of the remote device
307: */
308: public void removeConnection(String address) {
309: PicoNode pico = (PicoNode) piconet.get(address);
310: if (pico.connections == 0) {
311: throw new RuntimeException("No open connections for "
312: + address);
313: }
314: if (--pico.connections == 0) {
315: piconet.remove(address);
316: }
317: }
318:
319: /**
320: * Extracts initial configuration values from properties.
321: */
322: private void loadPropertyValues() {
323: // extract the bluetooth device power state
324: isBluetoothEnabled = getInternalBooleanProperty(
325: "bluetooth.enable", isBluetoothEnabled);
326:
327: // extract the device friendly name.
328: friendlyName = getInternalStringProperty(
329: "bluetooth.device.friendlyName", friendlyName);
330:
331: // extract the device class.
332: deviceClassBase = getInternalIntProperty(
333: "bluetooth.device.class", 16, deviceClassBase);
334:
335: // extract the discoverable mode.
336: accessCode = getInternalIntProperty(
337: "bluetooth.device.accessCode", 16, accessCode);
338: }
339:
340: /**
341: * Gets the internal property indicated by the specified key
342: * as an <code>String</code>
343: * or returns the specified default value if the property is not found.
344: *
345: * @param key the name of the internal property.
346: * @param def the default value for the property if there
347: * is no property with the key.
348: * @return the String value of the internal property
349: * or <code>def</code> if there is no property
350: * with that key.
351: *
352: * @exception NullPointerException if <code>key</code> is
353: * <code>null</code>.
354: * @exception IllegalArgumentException if <code>key</code> is empty.
355: */
356: private static String getInternalStringProperty(String key,
357: String def) {
358: // Implicitly throw NPE if key is null
359: if (key.length() == 0) {
360: throw new IllegalArgumentException("Key cannot be empty");
361: }
362:
363: String prop = Configuration.getProperty(key);
364: return (prop != null) ? prop : def;
365: }
366:
367: /**
368: * Gets the internal property indicated by the specified key
369: * as an <code>boolean</code>
370: * or returns the specified default value if property reading failed.
371: *
372: * @param key the name of the internal property.
373: * @param def the default value for the property if there
374: * is no property with the key.
375: * @return the boolean value of the internal property
376: * or <code>def</code> if there is no property
377: * with that key or the value is not valid.
378: *
379: * @exception NullPointerException if <code>key</code> is
380: * <code>null</code>.
381: * @exception IllegalArgumentException if <code>key</code> is empty.
382: */
383: private static boolean getInternalBooleanProperty(String key,
384: boolean def) {
385: // Implicitly throw NPE if key is null
386: if (key.length() == 0) {
387: throw new IllegalArgumentException("Key cannot be empty");
388: }
389:
390: boolean val = def;
391: String prop = Configuration.getProperty(key);
392: if (prop != null) {
393: if (prop.equalsIgnoreCase("true")
394: || prop.equalsIgnoreCase("yes")) {
395: val = true;
396: } else if (prop.equalsIgnoreCase("false")
397: || prop.equalsIgnoreCase("no")) {
398: val = false;
399: }
400: }
401: return val;
402: }
403:
404: /**
405: * Gets the internal property indicated by the specified key
406: * as an <code>int</code> in the specified radix
407: * or returns the specified default value if property reading failed.
408: *
409: * @param key the name of the internal property.
410: * @param radix the radix to be used.
411: * @param def the default value for the property if there
412: * is no property with the key.
413: * @return the integer value of the internal property
414: * or <code>def</code> if there is no property
415: * with that key or the value is not valid.
416: *
417: * @exception NullPointerException if <code>key</code> is
418: * <code>null</code>.
419: * @exception IllegalArgumentException if <code>key</code> is empty.
420: */
421: private static int getInternalIntProperty(String key, int radix,
422: int def) {
423: // Implicitly throws NPE if key is null
424: if (key.length() == 0) {
425: throw new IllegalArgumentException("Key cannot be empty");
426: }
427:
428: try {
429: String prop = Configuration.getProperty(key);
430: return Integer.parseInt(prop, radix);
431: } catch (NumberFormatException nfe) {
432: return def;
433: }
434: }
435:
436: }
|