View Javadoc

1   /**
2    *  BlueCove - Java library for Bluetooth
3    *  Copyright (C) 2006-2007 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: BluetoothTypesInfo.java 2562 2008-12-11 16:24:13Z skarzhevskyy $
24   */
25  
26  package net.sf.bluecove.util;
27  
28  import java.util.Enumeration;
29  import java.util.Hashtable;
30  import java.util.Vector;
31  
32  import javax.bluetooth.DataElement;
33  import javax.bluetooth.DeviceClass;
34  import javax.bluetooth.ServiceRecord;
35  import javax.bluetooth.UUID;
36  import javax.obex.ResponseCodes;
37  
38  import net.sf.bluecove.Consts;
39  
40  public abstract class BluetoothTypesInfo {
41  
42  	public static final String NULL = "{null}";
43  
44  	public static final String PROTOCOL_SCHEME_L2CAP = "btl2cap";
45  
46  	public static final String PROTOCOL_SCHEME_RFCOMM = "btspp";
47  
48  	public static final String PROTOCOL_SCHEME_BT_OBEX = "btgoep";
49  
50  	public static final String PROTOCOL_SCHEME_TCP_OBEX = "tcpobex";
51  
52  	public static final int ServiceClassIDList = 0x0001;
53  
54  	public static String extractBluetoothAddress(String serverURL) {
55  		int start = serverURL.indexOf("//");
56  		if (start == -1) {
57  			return null;
58  		}
59  		start += 2;
60  		int end = serverURL.indexOf(":", start);
61  		if (end == -1) {
62  			return null;
63  		}
64  		return serverURL.substring(start, end);
65  	}
66  
67  	public static boolean isRFCOMM(String serverURL) {
68  		return ((serverURL != null) && (serverURL.startsWith(PROTOCOL_SCHEME_RFCOMM)));
69  	}
70  
71  	public static boolean isL2CAP(String serverURL) {
72  		return ((serverURL != null) && (serverURL.startsWith(PROTOCOL_SCHEME_L2CAP)));
73  	}
74  
75  	public static class UUIDConsts {
76  
77  		private static String SHORT_BASE = "00001000800000805F9B34FB";
78  
79  		private static Hashtable uuidNames = new Hashtable();
80  
81  		private static void addName(String uuid, String name) {
82  			uuidNames.put(uuid.toUpperCase(), name);
83  		}
84  
85  		private static void addName(int uuid, String name) {
86  			addName(new UUID(uuid).toString(), name);
87  		}
88  
89  		static {
90  			addName(0x0001, "SDP");
91  			addName(0x0002, "UDP");
92  			addName(0x0003, "RFCOMM");
93  			addName(0x0004, "TCP");
94  			addName(0x0008, "OBEX");
95  			addName(0x000C, "HTTP");
96  			addName(0x000F, "BNEP");
97  			addName(0x0100, "L2CAP");
98  
99  			addName(0x1000, "SDP_SERVER");
100 			addName(0x1001, "BROWSE_GROUP_DESCRIPTOR");
101 			addName(0x1002, "PUBLICBROWSE_GROUP");
102 			addName(0x1101, "SERIAL_PORT");
103 			addName(0x1102, "LAN_ACCESS_PPP");
104 			addName(0x1103, "DIALUP_NETWORKING");
105 			addName(0x1104, "IR_MC_SYNC");
106 			addName(0x1105, "OBEX_OBJECT_PUSH");
107 			addName(0x1106, "OBEX_FILE_TRANSFER");
108 			addName(0x1107, "IR_MC_SYNC_COMMAND");
109 			addName(0x1108, "HEADSET");
110 			addName(0x1109, "CORDLESS_TELEPHONY");
111 			addName(0x110A, "AUDIO_SOURCE");
112 			addName(0x110B, "AUDIO_SINK");
113 			addName(0x110C, "AV_REMOTE_CTL_TARGET");
114 			addName(0x110D, "ADVANCED_AUDIO_DISTRIB");
115 			addName(0x110E, "AV_REMOTE_CTL");
116 			addName(0x110F, "VIDEO_CONFERENCING");
117 			addName(0x1110, "INTERCOM");
118 			addName(0x1111, "FAX");
119 			addName(0x1112, "HEADSET_AUDIO_GATEWAY");
120 			addName(0x1113, "WAP");
121 			addName(0x1114, "WAP_CLIENT");
122 			addName(0x1115, "PAN_USER");
123 			addName(0x1116, "NETWORK_ACCESS_POINT");
124 			addName(0x1117, "GROUP_NETWORK");
125 			addName(0x1118, "DIRECT_PRINTING");
126 			addName(0x1119, "REFERENCE_PRINTING");
127 			addName(0x111A, "IMG");
128 			addName(0x111B, "IMG_RESPONDER");
129 			addName(0x111C, "IMG_AUTO_ARCHIVE");
130 			addName(0x111D, "IMG_REFERENCE_OBJECTS");
131 			addName(0x111E, "HANDSFREE");
132 			addName(0x111F, "HANDSFREE_AUDIO_GATEWAY");
133 			addName(0x1120, "DIRECT_PRINT");
134 			addName(0x1121, "REFLECTED_UI");
135 			addName(0x1122, "BASIC_PRINTING");
136 			addName(0x1123, "PRINTING_STATUS");
137 			addName(0x1124, "HI_DEVICE");
138 			addName(0x1125, "HARD_COPY_CABLE_REPLACE");
139 			addName(0x1126, "HCR_PRINT");
140 			addName(0x1127, "HCR_SCAN");
141 			addName(0x1128, "COMMON_ISDN_ACCESS");
142 			addName(0x1129, "VIDEO_CONF_GW");
143 			addName(0x112A, "UDI_MT");
144 			addName(0x112B, "UDI_TA");
145 			addName(0x112C, "AUDIO_VIDEO");
146 			addName(0x112D, "SIM_ACCESS");
147 			addName(0x1200, "PNP_INFO");
148 			addName(0x1201, "GENERIC_NETWORKING");
149 			addName(0x1202, "GENERIC_FILE_TRANSFER");
150 			addName(0x1203, "GENERIC_AUDIO");
151 			addName(0x1204, "GENERIC_TELEPHONY");
152 			addName(0x1205, "UPNP_SERVICE");
153 			addName(0x1206, "UPNP_IP_SERVICE");
154 			addName(0x1300, "ESDP_UPNP_IP_PAN");
155 			addName(0x1301, "ESDP_UPNP_IP_LAP");
156 			addName(0x1302, "ESDP_UPNP_L2CAP");
157 
158 			addName(Consts.RESPONDER_SHORT_UUID, "BlueCoveT RFCOMM short");
159 			addName(Consts.RESPONDER_LONG_UUID, "BlueCoveT RFCOMM long");
160 
161 			addName(Consts.RESPONDER_SHORT_UUID_L2CAP, "BlueCoveT L2CAP short");
162 			addName(Consts.RESPONDER_LONG_UUID_L2CAP, "BlueCoveT L2CAP long");
163 
164 			addName(Consts.RESPONDER_LONG_UUID_OBEX, "BlueCoveT OBEX");
165 
166 			addName(Consts.RESPONDER_SERVICECLASS_UUID, "BlueCoveT SrvClassExt");
167 
168 			addName("3B9FA89520078C303355AAA694238F07", "JSR-82 TCK L2CAP AGENT");
169 			addName("2000000031b811d88698000874b33fc0", "JSR-82 TCK RFCOMM AGENT");
170 			addName("3000000031b811d88698000874b33fc0", "JSR-82 TCK BTGOEP AGENT");
171 			addName("4000000031b811d88698000874b33fc0", "JSR-82 OBEX TCK AGENT");
172 			addName("102030405060708090A1B1C1D1D1E100", "JSR-82 TCK");
173 
174 		}
175 
176 		public static String getName(UUID uuid) {
177 			if (uuid == null) {
178 				return null;
179 			}
180 			String str = uuid.toString().toUpperCase();
181 			String name = (String) uuidNames.get(str);
182 			if (name != null) {
183 				return name;
184 			}
185 			int shortIdx = str.indexOf(SHORT_BASE);
186 			if ((shortIdx != -1) && (shortIdx + SHORT_BASE.length() == str.length())) {
187 				// This is short 16-bit or 32-bit UUID
188 				return toHexString(Integer.parseInt(str.substring(0, shortIdx), 16));
189 			}
190 			return null;
191 		}
192 
193 		public static UUID getUUID(String uuidValue) {
194 			if (uuidValue == null) {
195 				return null;
196 			}
197 			String uuidValueUpper = uuidValue.toUpperCase();
198 			if (uuidNames.contains(uuidValueUpper)) {
199 				for (Enumeration iter = uuidNames.keys(); iter.hasMoreElements();) {
200 					String uuidValueKey = (String) iter.nextElement();
201 					String name = (String) uuidNames.get(uuidValueKey);
202 					if ((name != null) && (uuidValueUpper.equals(name))) {
203 						return new UUID(uuidValueKey, false);
204 					}
205 				}
206 			}
207 			UUID uuid;
208 			if (uuidValue.startsWith("0x")) {
209                 uuidValue = uuidValue.substring(2);
210             } else if (uuidValue.endsWith("l")) {
211                 return new UUID(Long.parseLong(uuidValue.substring(0, uuidValue.length() - 1)));
212             }
213 			if (uuidValue.length() <= 8) {
214 				uuid = new UUID(uuidValue, true);
215 			} else {
216 				uuid = new UUID(uuidValue, false);
217 			}
218 			return uuid;
219 		}
220 	}
221 
222 	public static String toString(ServiceRecord sr) {
223 		if (sr == null) {
224 			return NULL;
225 		}
226 		int[] ids = sr.getAttributeIDs();
227 		if (ids == null) {
228 			return "attributes " + NULL;
229 		}
230 		if (ids.length == 0) {
231 			return "no attributes";
232 		}
233 		Vector sorted = new Vector();
234 		for (int i = 0; i < ids.length; i++) {
235 			sorted.addElement(new Integer(ids[i]));
236 		}
237 		CollectionUtils.sort(sorted);
238 		StringBuffer buf = new StringBuffer();
239 		for (Enumeration en = sorted.elements(); en.hasMoreElements();) {
240 			int id = ((Integer) en.nextElement()).intValue();
241 			buf.append(toHexString(id));
242 			buf.append(" ");
243 			buf.append(toStringServiceAttributeID(id));
244 			buf.append(":  ");
245 
246 			DataElement d = sr.getAttributeValue(id);
247 			buf.append(toString(d));
248 			buf.append("\n");
249 		}
250 		return buf.toString();
251 	}
252 
253 	public static String toStringServiceAttributeID(int id) {
254 		switch (id) {
255 		case 0x0000:
256 			return "ServiceRecordHandle";
257 		case 0x0001:
258 			return "ServiceClassIDList";
259 		case 0x0002:
260 			return "ServiceRecordState";
261 		case 0x0003:
262 			return "ServiceID";
263 		case 0x0004:
264 			return "ProtocolDescriptorList";
265 		case 0x0005:
266 			return "BrowseGroupList";
267 		case 0x0006:
268 			return "LanguageBasedAttributeIDList";
269 		case 0x0007:
270 			return "ServiceInfoTimeToLive";
271 		case 0x0008:
272 			return "ServiceAvailability";
273 		case 0x0009:
274 			return "BluetoothProfileDescriptorList";
275 		case 0x000A:
276 			return "DocumentationURL";
277 		case 0x000B:
278 			return "ClientExecutableURL";
279 		case 0x000C:
280 			return "IconURL";
281 		case 0x000D:
282 			return "AdditionalProtocol";
283 		case 0x0100:
284 			return "ServiceName";
285 		case 0x0101:
286 			return "ServiceDescription";
287 		case 0x0102:
288 			return "ProviderName";
289 		case 0x0200:
290 			return "GroupID";
291 		case 0x0201:
292 			return "ServiceDatabaseState";
293 		case 0x0300:
294 			return "ServiceVersion";
295 		case 0x0301:
296 			return "ExternalNetwork";
297 		case 0x0302:
298 			return "RemoteAudioVolumeControl";
299 		case 0x0303:
300 			return "SupportedFormatList";
301 		case 0x0304:
302 			return "FaxClass2Support";
303 		case 0x0305:
304 			return "AudioFeedbackSupport";
305 		case 0x0306:
306 			return "NetworkAddress";
307 		case 0x0307:
308 			return "WAPGateway";
309 		case 0x0308:
310 			return "HomePageURL";
311 		case 0x0309:
312 			return "WAPStackType";
313 		case 0x030A:
314 			return "SecurityDescription";
315 		case 0x030B:
316 			return "NetAccessType";
317 		case 0x030C:
318 			return "MaxNetAccessrate";
319 		case 0x030D:
320 			return "IPv4Subnet";
321 		case 0x030E:
322 			return "IPv6Subnet";
323 		case 0x0310:
324 			return "SupportedCapabalities";
325 		case 0x0311:
326 			return "SupportedFeatures";
327 		case 0x0312:
328 			return "SupportedFunctions";
329 		case 0x0313:
330 			return "TotalImagingDataCapacity";
331 		default:
332 			return "";
333 		}
334 	}
335 
336 	public static String toStringDataElementType(int type) {
337 		switch (type) {
338 		case DataElement.NULL:
339 			return "NULL";
340 		case DataElement.U_INT_1:
341 			return "U_INT_1";
342 		case DataElement.U_INT_2:
343 			return "U_INT_2";
344 		case DataElement.U_INT_4:
345 			return "U_INT_4";
346 		case DataElement.U_INT_8:
347 			return "U_INT_8";
348 		case DataElement.U_INT_16:
349 			return "U_INT_16";
350 		case DataElement.INT_1:
351 			return "INT_1";
352 		case DataElement.INT_2:
353 			return "INT_2";
354 		case DataElement.INT_4:
355 			return "INT_4";
356 		case DataElement.INT_8:
357 			return "INT_8";
358 		case DataElement.INT_16:
359 			return "INT_16";
360 		case DataElement.URL:
361 			return "URL";
362 		case DataElement.STRING:
363 			return "STRING";
364 		case DataElement.UUID:
365 			return "UUID";
366 		case DataElement.DATSEQ:
367 			return "DATSEQ";
368 		case DataElement.BOOL:
369 			return "BOOL";
370 		case DataElement.DATALT:
371 			return "DATALT";
372 		default:
373 			return "Unknown" + type;
374 		}
375 	}
376 
377 	public static String toStringObexResponseCodes(int code) {
378 		switch (code) {
379 		case 0x90:
380 			return "OBEX_RESPONSE_CONTINUE";
381 		case ResponseCodes.OBEX_HTTP_OK:
382 			return "OBEX_HTTP_OK";
383 		case ResponseCodes.OBEX_HTTP_CREATED:
384 			return "OBEX_HTTP_CREATED";
385 		case ResponseCodes.OBEX_HTTP_ACCEPTED:
386 			return "OBEX_HTTP_ACCEPTED";
387 		case ResponseCodes.OBEX_HTTP_NOT_AUTHORITATIVE:
388 			return "OBEX_HTTP_NOT_AUTHORITATIVE";
389 		case ResponseCodes.OBEX_HTTP_NO_CONTENT:
390 			return "OBEX_HTTP_NO_CONTENT";
391 		case ResponseCodes.OBEX_HTTP_RESET:
392 			return "OBEX_HTTP_RESET";
393 		case ResponseCodes.OBEX_HTTP_PARTIAL:
394 			return "OBEX_HTTP_PARTIAL";
395 		case ResponseCodes.OBEX_HTTP_MULT_CHOICE:
396 			return "OBEX_HTTP_MULT_CHOICE";
397 		case ResponseCodes.OBEX_HTTP_MOVED_PERM:
398 			return "OBEX_HTTP_MOVED_PERM";
399 		case ResponseCodes.OBEX_HTTP_MOVED_TEMP:
400 			return "OBEX_HTTP_MOVED_TEMP";
401 		case ResponseCodes.OBEX_HTTP_SEE_OTHER:
402 			return "OBEX_HTTP_SEE_OTHER";
403 		case ResponseCodes.OBEX_HTTP_NOT_MODIFIED:
404 			return "OBEX_HTTP_NOT_MODIFIED";
405 		case ResponseCodes.OBEX_HTTP_USE_PROXY:
406 			return "OBEX_HTTP_USE_PROXY";
407 		case ResponseCodes.OBEX_HTTP_BAD_REQUEST:
408 			return "OBEX_HTTP_BAD_REQUEST";
409 		case ResponseCodes.OBEX_HTTP_UNAUTHORIZED:
410 			return "OBEX_HTTP_UNAUTHORIZED";
411 		case ResponseCodes.OBEX_HTTP_PAYMENT_REQUIRED:
412 			return "OBEX_HTTP_PAYMENT_REQUIRED";
413 		case ResponseCodes.OBEX_HTTP_FORBIDDEN:
414 			return "OBEX_HTTP_FORBIDDEN";
415 		case ResponseCodes.OBEX_HTTP_NOT_FOUND:
416 			return "OBEX_HTTP_NOT_FOUND";
417 		case ResponseCodes.OBEX_HTTP_BAD_METHOD:
418 			return "OBEX_HTTP_BAD_METHOD";
419 		case ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE:
420 			return "OBEX_HTTP_NOT_ACCEPTABLE";
421 		case ResponseCodes.OBEX_HTTP_PROXY_AUTH:
422 			return "OBEX_HTTP_PROXY_AUTH";
423 		case ResponseCodes.OBEX_HTTP_TIMEOUT:
424 			return "OBEX_HTTP_TIMEOUT";
425 		case ResponseCodes.OBEX_HTTP_CONFLICT:
426 			return "OBEX_HTTP_CONFLICT";
427 		case ResponseCodes.OBEX_HTTP_GONE:
428 			return "OBEX_HTTP_GONE";
429 		case ResponseCodes.OBEX_HTTP_LENGTH_REQUIRED:
430 			return "OBEX_HTTP_LENGTH_REQUIRED";
431 		case ResponseCodes.OBEX_HTTP_PRECON_FAILED:
432 			return "OBEX_HTTP_PRECON_FAILED";
433 		case ResponseCodes.OBEX_HTTP_ENTITY_TOO_LARGE:
434 			return "OBEX_HTTP_ENTITY_TOO_LARGE";
435 		case ResponseCodes.OBEX_HTTP_REQ_TOO_LARGE:
436 			return "OBEX_HTTP_REQ_TOO_LARGE";
437 		case ResponseCodes.OBEX_HTTP_UNSUPPORTED_TYPE:
438 			return "OBEX_HTTP_UNSUPPORTED_TYPE";
439 		case ResponseCodes.OBEX_HTTP_INTERNAL_ERROR:
440 			return "OBEX_HTTP_INTERNAL_ERROR";
441 		case ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED:
442 			return "OBEX_HTTP_NOT_IMPLEMENTED";
443 		case ResponseCodes.OBEX_HTTP_BAD_GATEWAY:
444 			return "OBEX_HTTP_BAD_GATEWAY";
445 		case ResponseCodes.OBEX_HTTP_UNAVAILABLE:
446 			return "OBEX_HTTP_UNAVAILABLE";
447 		case ResponseCodes.OBEX_HTTP_GATEWAY_TIMEOUT:
448 			return "OBEX_HTTP_GATEWAY_TIMEOUT";
449 		case ResponseCodes.OBEX_HTTP_VERSION:
450 			return "OBEX_HTTP_VERSION";
451 		case ResponseCodes.OBEX_DATABASE_FULL:
452 			return "OBEX_DATABASE_FULL";
453 		case ResponseCodes.OBEX_DATABASE_LOCKED:
454 			return "OBEX_DATABASE_LOCKED";
455 		default:
456 			return "Unknown " + toHexString(code);
457 		}
458 	}
459 
460 	public static String toHexStringSigned(long l) {
461 		if (l >= 0) {
462 			return toHexString(l);
463 		} else {
464 			return "-" + toHexString(-l);
465 		}
466 	}
467 
468 	public static String toHexString(long l) {
469 		if (l > 0xffffffffl) {
470 			String lo = Integer.toHexString((int) l);
471 			while (lo.length() < 8) {
472 				lo = "0" + lo;
473 			}
474 			return "0x" + Integer.toHexString((int) (l >> 32)) + lo;
475 		} else {
476 			return "0x" + Integer.toHexString((int) l);
477 		}
478 	}
479 
480 	public static String toHexString(int i) {
481 		String s = Integer.toHexString(i);
482 		s = s.toUpperCase();
483 		switch (s.length()) {
484 		case 1:
485 			return "0x000" + s;
486 		case 2:
487 			return "0x00" + s;
488 		case 3:
489 			return "0x0" + s;
490 		case 4:
491 			return "0x" + s;
492 		default:
493 			return s;
494 		}
495 	}
496 
497 	public static String toString(DataElement d) {
498 		return toString(d, "");
499 	}
500 
501 	public static String toString(DataElement d, String ident) {
502 		if (d == null) {
503 			return NULL;
504 		}
505 		StringBuffer buf = new StringBuffer();
506 
507 		int valueType = d.getDataType();
508 		buf.append(ident);
509 		buf.append(toStringDataElementType(valueType));
510 
511 		switch (valueType) {
512 		case DataElement.U_INT_1:
513 		case DataElement.U_INT_2:
514 		case DataElement.U_INT_4:
515 			buf.append(" ").append(toHexString(d.getLong()));
516 			break;
517 		case DataElement.INT_1:
518 		case DataElement.INT_2:
519 		case DataElement.INT_4:
520 		case DataElement.INT_8:
521 			buf.append(" ").append(toHexStringSigned(d.getLong()));
522 			break;
523 		case DataElement.BOOL:
524 			buf.append(" ").append(d.getBoolean());
525 			break;
526 		case DataElement.URL:
527 		case DataElement.STRING:
528 			buf.append(" ").append(d.getValue());
529 			break;
530 		case DataElement.UUID:
531 			buf.append(" ").append(toString((UUID) d.getValue()));
532 			break;
533 		case DataElement.U_INT_8:
534 		case DataElement.U_INT_16:
535 		case DataElement.INT_16:
536 			byte[] b = (byte[]) d.getValue();
537 			buf.append(" ");
538 			for (int i = 0; i < b.length; i++) {
539 				buf.append(Integer.toHexString(b[i] >> 4 & 0xf));
540 				buf.append(Integer.toHexString(b[i] & 0xf));
541 			}
542 			break;
543 		case DataElement.DATALT:
544 		case DataElement.DATSEQ:
545 			buf.append(" {\n");
546 			for (Enumeration e = (Enumeration) (d.getValue()); e.hasMoreElements();) {
547 				buf.append(toString((DataElement) e.nextElement(), ident + "  ")).append("\n");
548 			}
549 			buf.append(ident).append("}");
550 			break;
551 		}
552 		return buf.toString();
553 	}
554 
555 	public static String toString(UUID uuid) {
556 		if (uuid == null) {
557 			return NULL;
558 		}
559 		StringBuffer buf = new StringBuffer();
560 		buf.append(uuid.toString());
561 		String name = UUIDConsts.getName(uuid);
562 		if (name != null) {
563 			buf.append(" (").append(name).append(")");
564 		}
565 		return buf.toString();
566 	}
567 
568 	public static String toString(DeviceClass dc) {
569 		return DeviceClassConsts.toString(dc);
570 	}
571 
572 	public static class DeviceClassConsts {
573 
574 		/*
575 		 * service classes
576 		 */
577 
578 		public static final int LIMITED_DISCOVERY_SERVICE = 0x002000;
579 
580 		public static final int RESERVED1_SERVICE = 0x004000;
581 
582 		public static final int RESERVED2_SERVICE = 0x008000;
583 
584 		public static final int POSITIONING_SERVICE = 0x010000;
585 
586 		public static final int NETWORKING_SERVICE = 0x020000;
587 
588 		public static final int RENDERING_SERVICE = 0x040000;
589 
590 		public static final int CAPTURING_SERVICE = 0x080000;
591 
592 		public static final int OBJECT_TRANSFER_SERVICE = 0x100000;
593 
594 		public static final int AUDIO_SERVICE = 0x200000;
595 
596 		public static final int TELEPHONY_SERVICE = 0x400000;
597 
598 		public static final int INFORMATION_SERVICE = 0x800000;
599 
600 		/*
601 		 * major class codes
602 		 */
603 
604 		public static final int MAJOR_MISCELLANEOUS = 0x0000;
605 
606 		public static final int MAJOR_COMPUTER = 0x0100;
607 
608 		public static final int MAJOR_PHONE = 0x0200;
609 
610 		public static final int MAJOR_LAN_ACCESS = 0x0300;
611 
612 		public static final int MAJOR_AUDIO = 0x0400;
613 
614 		public static final int MAJOR_PERIPHERAL = 0x0500;
615 
616 		public static final int MAJOR_IMAGING = 0x0600;
617 
618 		public static final int MAJOR_UNCLASSIFIED = 0x1F00;
619 
620 		/*
621 		 * minor class codes
622 		 */
623 
624 		public static final int COMPUTER_MINOR_UNCLASSIFIED = 0x00;
625 
626 		public static final int COMPUTER_MINOR_DESKTOP = 0x04;
627 
628 		public static final int COMPUTER_MINOR_SERVER = 0x08;
629 
630 		public static final int COMPUTER_MINOR_LAPTOP = 0x0c;
631 
632 		public static final int COMPUTER_MINOR_HANDHELD = 0x10;
633 
634 		public static final int COMPUTER_MINOR_PALM = 0x14;
635 
636 		public static final int COMPUTER_MINOR_WEARABLE = 0x18;
637 
638 		public static final int PHONE_MINOR_UNCLASSIFIED = 0x00;
639 
640 		public static final int PHONE_MINOR_CELLULAR = 0x04;
641 
642 		public static final int PHONE_MINOR_CORDLESS = 0x08;
643 
644 		public static final int PHONE_MINOR_SMARTPHONE = 0x0c;
645 
646 		public static final int PHONE_MINOR_WIRED_MODEM = 0x10;
647 
648 		public static final int PHONE_MINOR_ISDN = 0x14;
649 
650 		public static final int PHONE_MINOR_BANANA = 0x18;
651 
652 		public static final int LAN_MINOR_TYPE_MASK = 0x1c;
653 
654 		public static final int LAN_MINOR_ACCESS_MASK = 0xe0;
655 
656 		public static final int LAN_MINOR_UNCLASSIFIED = 0x00;
657 
658 		public static final int LAN_MINOR_ACCESS_0_USED = 0x00;
659 
660 		public static final int LAN_MINOR_ACCESS_17_USED = 0x20;
661 
662 		public static final int LAN_MINOR_ACCESS_33_USED = 0x40;
663 
664 		public static final int LAN_MINOR_ACCESS_50_USED = 0x60;
665 
666 		public static final int LAN_MINOR_ACCESS_67_USED = 0x80;
667 
668 		public static final int LAN_MINOR_ACCESS_83_USED = 0xa0;
669 
670 		public static final int LAN_MINOR_ACCESS_99_USED = 0xc0;
671 
672 		public static final int LAN_MINOR_ACCESS_FULL = 0xe0;
673 
674 		public static final int AUDIO_MINOR_UNCLASSIFIED = 0x00;
675 
676 		public static final int AUDIO_MINOR_HEADSET = 0x04;
677 
678 		public static final int AUDIO_MINOR_HANDS_FREE = 0x08;
679 
680 		// public static final int AUDIO_MINOR_RESERVED = 0x0c;
681 		public static final int AUDIO_MINOR_MICROPHONE = 0x10;
682 
683 		public static final int AUDIO_MINOR_LOUDSPEAKER = 0x14;
684 
685 		public static final int AUDIO_MINOR_HEADPHONES = 0x18;
686 
687 		public static final int AUDIO_MINOR_PORTABLE_AUDIO = 0x1c;
688 
689 		public static final int AUDIO_MINOR_CAR_AUDIO = 0x20;
690 
691 		public static final int AUDIO_MINOR_SET_TOP_BOX = 0x24;
692 
693 		public static final int AUDIO_MINOR_HIFI_AUDIO = 0x28;
694 
695 		public static final int AUDIO_MINOR_VCR = 0x2c;
696 
697 		public static final int AUDIO_MINOR_VIDEO_CAMERA = 0x30;
698 
699 		public static final int AUDIO_MINOR_CAMCORDER = 0x34;
700 
701 		public static final int AUDIO_MINOR_VIDEO_MONITOR = 0x38;
702 
703 		public static final int AUDIO_MINOR_VIDEO_DISPLAY_LOUDSPEAKER = 0x3c;
704 
705 		public static final int AUDIO_MINOR_VIDEO_DISPLAY_CONFERENCING = 0x40;
706 
707 		// public static final int AUDIO_MINOR_RESERVED = 0x44;
708 		public static final int AUDIO_MINOR_GAMING_TOY = 0x48;
709 
710 		public static final int PERIPHERAL_MINOR_TYPE_MASK = 0x3c;
711 
712 		public static final int PERIPHERAL_MINOR_KEYBOARD_MASK = 0x40;
713 
714 		public static final int PERIPHERAL_MINOR_POINTER_MASK = 0x80;
715 
716 		public static final int PERIPHERAL_MINOR_UNCLASSIFIED = 0x00;
717 
718 		public static final int PERIPHERAL_MINOR_JOYSTICK = 0x04;
719 
720 		public static final int PERIPHERAL_MINOR_GAMEPAD = 0x08;
721 
722 		public static final int PERIPHERAL_MINOR_REMOTE_CONTROL = 0x0c;
723 
724 		public static final int PERIPHERAL_MINOR_SENSING = 0x10;
725 
726 		public static final int PERIPHERAL_MINOR_DIGITIZER = 0x14;
727 
728 		public static final int PERIPHERAL_MINOR_CARD_READER = 0x18;
729 
730 		public static final int IMAGING_MINOR_DISPLAY_MASK = 0x10;
731 
732 		public static final int IMAGING_MINOR_CAMERA_MASK = 0x20;
733 
734 		public static final int IMAGING_MINOR_SCANNER_MASK = 0x40;
735 
736 		public static final int IMAGING_MINOR_PRINTER_MASK = 0x80;
737 
738 		private static boolean append(StringBuffer buf, String str, boolean comma) {
739 			if (comma) {
740 				buf.append(',');
741 			}
742 
743 			buf.append(str);
744 
745 			return true;
746 		}
747 
748 		public static String toString(DeviceClass dc) {
749 			if (dc == null) {
750 				return NULL;
751 			}
752 			StringBuffer buf = new StringBuffer();
753 
754 			switch (dc.getMajorDeviceClass()) {
755 			case MAJOR_MISCELLANEOUS:
756 				buf.append("Miscellaneous");
757 				break;
758 			case MAJOR_COMPUTER:
759 				buf.append("Computer");
760 
761 				switch (dc.getMinorDeviceClass()) {
762 				case COMPUTER_MINOR_UNCLASSIFIED:
763 					buf.append("/Unclassified");
764 					break;
765 				case COMPUTER_MINOR_DESKTOP:
766 					buf.append("/Desktop");
767 					break;
768 				case COMPUTER_MINOR_SERVER:
769 					buf.append("/Server");
770 					break;
771 				case COMPUTER_MINOR_LAPTOP:
772 					buf.append("/Laptop");
773 					break;
774 				case COMPUTER_MINOR_HANDHELD:
775 					buf.append("/Handheld");
776 					break;
777 				case COMPUTER_MINOR_PALM:
778 					buf.append("/Palm");
779 					break;
780 				case COMPUTER_MINOR_WEARABLE:
781 					buf.append("/Wearable");
782 					break;
783 				default:
784 					buf.append("/Unknown");
785 					break;
786 				}
787 
788 				break;
789 			case MAJOR_PHONE:
790 				buf.append("Phone");
791 
792 				switch (dc.getMinorDeviceClass()) {
793 				case PHONE_MINOR_UNCLASSIFIED:
794 					buf.append("/Unclassified");
795 					break;
796 				case PHONE_MINOR_CELLULAR:
797 					buf.append("/Cellular");
798 					break;
799 				case PHONE_MINOR_CORDLESS:
800 					buf.append("/Cordless");
801 					break;
802 				case PHONE_MINOR_SMARTPHONE:
803 					buf.append("/Smartphone");
804 					break;
805 				case PHONE_MINOR_WIRED_MODEM:
806 					buf.append("/Wired Modem");
807 					break;
808 				case PHONE_MINOR_ISDN:
809 					buf.append("/ISDN");
810 					break;
811 				case PHONE_MINOR_BANANA:
812 					buf.append("/Ring ring ring ring ring ring ring");
813 					break;
814 				default:
815 					buf.append("/Unknown");
816 					break;
817 				}
818 
819 				break;
820 			case MAJOR_LAN_ACCESS: {
821 				buf.append("LAN Access");
822 
823 				int minor = dc.getMinorDeviceClass();
824 
825 				switch (minor & LAN_MINOR_TYPE_MASK) {
826 				case LAN_MINOR_UNCLASSIFIED:
827 					buf.append("/Unclassified");
828 					break;
829 				default:
830 					buf.append("/Unknown");
831 					break;
832 				}
833 
834 				switch (minor & LAN_MINOR_ACCESS_MASK) {
835 				case LAN_MINOR_ACCESS_0_USED:
836 					buf.append("/0% used");
837 					break;
838 				case LAN_MINOR_ACCESS_17_USED:
839 					buf.append("/1-17% used");
840 					break;
841 				case LAN_MINOR_ACCESS_33_USED:
842 					buf.append("/18-33% used");
843 					break;
844 				case LAN_MINOR_ACCESS_50_USED:
845 					buf.append("/34-50% used");
846 					break;
847 				case LAN_MINOR_ACCESS_67_USED:
848 					buf.append("/51-67% used");
849 					break;
850 				case LAN_MINOR_ACCESS_83_USED:
851 					buf.append("/68-83% used");
852 					break;
853 				case LAN_MINOR_ACCESS_99_USED:
854 					buf.append("/84-99% used");
855 					break;
856 				case LAN_MINOR_ACCESS_FULL:
857 					buf.append("/100% used");
858 					break;
859 				}
860 
861 				break;
862 			}
863 			case MAJOR_AUDIO:
864 				buf.append("Audio");
865 
866 				switch (dc.getMinorDeviceClass()) {
867 				case AUDIO_MINOR_UNCLASSIFIED:
868 					buf.append("/Unclassified");
869 					break;
870 				case AUDIO_MINOR_HEADSET:
871 					buf.append("/Headset");
872 					break;
873 				case AUDIO_MINOR_HANDS_FREE:
874 					buf.append("/Hands-free");
875 					break;
876 				case AUDIO_MINOR_MICROPHONE:
877 					buf.append("/Microphone");
878 					break;
879 				case AUDIO_MINOR_LOUDSPEAKER:
880 					buf.append("/Loudspeaker");
881 					break;
882 				case AUDIO_MINOR_HEADPHONES:
883 					buf.append("/Headphones");
884 					break;
885 				case AUDIO_MINOR_PORTABLE_AUDIO:
886 					buf.append("/Portable");
887 					break;
888 				case AUDIO_MINOR_CAR_AUDIO:
889 					buf.append("/Car");
890 					break;
891 				case AUDIO_MINOR_SET_TOP_BOX:
892 					buf.append("/Set-top Box");
893 					break;
894 				case AUDIO_MINOR_HIFI_AUDIO:
895 					buf.append("/HiFi");
896 					break;
897 				case AUDIO_MINOR_VCR:
898 					buf.append("/VCR");
899 					break;
900 				case AUDIO_MINOR_VIDEO_CAMERA:
901 					buf.append("/Video Camera");
902 					break;
903 				case AUDIO_MINOR_CAMCORDER:
904 					buf.append("/Camcorder");
905 					break;
906 				case AUDIO_MINOR_VIDEO_MONITOR:
907 					buf.append("/Video Monitor");
908 					break;
909 				case AUDIO_MINOR_VIDEO_DISPLAY_LOUDSPEAKER:
910 					buf.append("/Video Display Loudspeaker");
911 					break;
912 				case AUDIO_MINOR_VIDEO_DISPLAY_CONFERENCING:
913 					buf.append("/Video Display Conferencing");
914 					break;
915 				case AUDIO_MINOR_GAMING_TOY:
916 					buf.append("/Gaming Toy");
917 					break;
918 				default:
919 					buf.append("/Unknown");
920 					break;
921 				}
922 
923 				break;
924 			case MAJOR_PERIPHERAL: {
925 				buf.append("Peripheral");
926 
927 				int minor = dc.getMinorDeviceClass();
928 
929 				switch (minor & (PERIPHERAL_MINOR_KEYBOARD_MASK | PERIPHERAL_MINOR_POINTER_MASK)) {
930 				case 0:
931 					buf.append("/()");
932 					break;
933 				case PERIPHERAL_MINOR_KEYBOARD_MASK:
934 					buf.append("/(Keyboard)");
935 					break;
936 				case PERIPHERAL_MINOR_POINTER_MASK:
937 					buf.append("/(Pointer)");
938 					break;
939 				case PERIPHERAL_MINOR_KEYBOARD_MASK | PERIPHERAL_MINOR_POINTER_MASK:
940 					buf.append("/(Keyboard,Pointer)");
941 					break;
942 				}
943 
944 				switch (minor & PERIPHERAL_MINOR_TYPE_MASK) {
945 				case PERIPHERAL_MINOR_UNCLASSIFIED:
946 					buf.append("/Unclassified");
947 					break;
948 				case PERIPHERAL_MINOR_JOYSTICK:
949 					buf.append("/Joystick");
950 					break;
951 				case PERIPHERAL_MINOR_GAMEPAD:
952 					buf.append("/Gamepad");
953 					break;
954 				case PERIPHERAL_MINOR_REMOTE_CONTROL:
955 					buf.append("/Remote Control");
956 					break;
957 				case PERIPHERAL_MINOR_SENSING:
958 					buf.append("/Sensing");
959 					break;
960 				case PERIPHERAL_MINOR_DIGITIZER:
961 					buf.append("/Digitizer");
962 					break;
963 				case PERIPHERAL_MINOR_CARD_READER:
964 					buf.append("/Card Reader");
965 					break;
966 				default:
967 					buf.append("/Unknown");
968 					break;
969 				}
970 
971 				break;
972 			}
973 			case MAJOR_IMAGING: {
974 				buf.append("Peripheral/(");
975 
976 				int minor = dc.getMinorDeviceClass();
977 
978 				boolean comma = false;
979 
980 				if ((minor & IMAGING_MINOR_DISPLAY_MASK) != 0)
981 					comma = append(buf, "Display", comma);
982 				if ((minor & IMAGING_MINOR_CAMERA_MASK) != 0)
983 					comma = append(buf, "Camera", comma);
984 				if ((minor & IMAGING_MINOR_SCANNER_MASK) != 0)
985 					comma = append(buf, "Scanner", comma);
986 				if ((minor & IMAGING_MINOR_PRINTER_MASK) != 0)
987 					comma = append(buf, "Printer", comma);
988 
989 				buf.append(')');
990 
991 				break;
992 			}
993 			case MAJOR_UNCLASSIFIED:
994 				buf.append("Unclassified");
995 				break;
996 			default:
997 				buf.append("Unknown");
998 				break;
999 			}
1000 
1001 			buf.append("(");
1002 
1003 			boolean comma = false;
1004 
1005 			int record = dc.getServiceClasses();
1006 
1007 			if ((record & LIMITED_DISCOVERY_SERVICE) != 0)
1008 				comma = append(buf, "Limited Discovery", comma);
1009 			if ((record & POSITIONING_SERVICE) != 0)
1010 				comma = append(buf, "Positioning", comma);
1011 			if ((record & NETWORKING_SERVICE) != 0)
1012 				comma = append(buf, "Networking", comma);
1013 			if ((record & RENDERING_SERVICE) != 0)
1014 				comma = append(buf, "Rendering", comma);
1015 			if ((record & CAPTURING_SERVICE) != 0)
1016 				comma = append(buf, "Capturing", comma);
1017 			if ((record & OBJECT_TRANSFER_SERVICE) != 0)
1018 				comma = append(buf, "Object Transfer", comma);
1019 			if ((record & AUDIO_SERVICE) != 0)
1020 				comma = append(buf, "Audio", comma);
1021 			if ((record & TELEPHONY_SERVICE) != 0)
1022 				comma = append(buf, "Telephony", comma);
1023 			if ((record & INFORMATION_SERVICE) != 0)
1024 				comma = append(buf, "Information", comma);
1025 
1026 			buf.append(')');
1027 
1028 			return buf.toString();
1029 		}
1030 	}
1031 }