package com.mobilesorcery.sdk.ui.targetphone.internal.bt; import java.io.IOException; import java.util.Comparator; import java.util.HashMap; import javax.bluetooth.DeviceClass; import javax.bluetooth.RemoteDevice; import com.mobilesorcery.sdk.core.Util; import com.mobilesorcery.sdk.ui.targetphone.internal.bt.BluetoothDialog.DeviceUpdate; /** * Represents a single bluetooth device that has been discovered. * * @author fmattias */ public class BluetoothDevice { /** * Returns the type of this bluetooth device, i.e. whether * it is a phone, laptop or a stationary computer. * @author fmattias * */ public enum Type { PHONE, /* Mobile phone */ LAPTOP, /* Laptop */ COMPUTER, /* Computer */ UNKNOWN }; /** * A map from a property name to a property. */ private HashMap<String, String> m_properties = new HashMap<String, String>(); /** * The type of the device, i.e. laptop, phone or computer. */ private Type m_deviceType; private RemoteDevice m_device; protected long m_getDiscoveryTimestamp; private static final int ADDRESS_LENGTH = 6; public static final Comparator<BluetoothDevice> COMPARATOR = new Comparator<BluetoothDevice>() { public int compare(BluetoothDevice device1, BluetoothDevice device2) { int result = device1.m_deviceType.compareTo(device2.m_deviceType); if (result == 0) { result = new Long(device1.m_getDiscoveryTimestamp).compareTo(device2.m_getDiscoveryTimestamp); if (result == 0) { return new Integer(System.identityHashCode(device1)).compareTo(System.identityHashCode(device2)); } } return result; } }; /** * Creates a device with the given properties. * * @param name * @param address * @param deviceType */ public BluetoothDevice(String name, String address, Type deviceType) { m_properties.put( "name", name ); m_properties.put( "address", address ); m_deviceType = deviceType; } /** * Creates a device from a discovered device. The name of the device * will be resolved in this function. * * @param device A device that has been discovered. * @param deviceClass The type of the device, i.e. the major and minor * device class of the bluetooth protocol. */ public BluetoothDevice(final RemoteDevice device, DeviceClass deviceClass) { // Ok, let's just for now assume creation time = discovery time... m_getDiscoveryTimestamp = System.currentTimeMillis(); m_properties.put( "name", ""); m_properties.put( "address", device.getBluetoothAddress( ) ); m_device = device; m_deviceType = getType( deviceClass.getMajorDeviceClass( ), deviceClass.getMinorDeviceClass( ) ); } /** * Converts the given minor and major device * class to the Type enum. * * @param majorClass The major class of the device (see bluetooth spec). * @param minorClass The minor class of the device (see bluetooth spec). * * @return The classes converted to an enum. */ private Type getType(int majorClass, int minorClass) { /* Find type of device. */ if( majorClass == 0x100 ) { if( minorClass == 0xC ) { return Type.LAPTOP; } else { return Type.COMPUTER; } } else if( majorClass == 0x200 ) { return Type.PHONE; } return Type.UNKNOWN; } /** * Returns the value corresponding to name. * * Currently these properties are supported: * name - Returns the name of the device. * address - Returns the mac address of the device. * * @param name * @return */ public String getProperty(String name) { return m_properties.get( name ); } /** * Returns the device class of this device. I.e. if it is a laptop, * computer or phone. * * @return The device class of this device. */ public Type getType() { return m_deviceType; } /** * Converts the current device structure to the one * used in btDialog. * * Note that the port will always be unassinged. * * @return the current device as a BTTargetPhone. */ public BTTargetPhone getTargetPhone() { char name[] = m_properties.get( "name" ).toCharArray( ); byte addr[] = new byte[ADDRESS_LENGTH]; /* Parse one byte at a time in the address, i.e. 2 hex chars. */ String addrStr = m_properties.get( "address" ); for(int i = 0; i < addrStr.length( ); i += 2) { int byteIndex = i / 2; String byteStr = addrStr.substring(i, i+2); // Not inclusive /* Convert from hex string to byte */ addr[ byteIndex ] = (byte) Integer.parseInt(byteStr, 16); } final BTTargetPhone result = new BTTargetPhone(Util.isEmpty(new String(name)) ? BTTargetPhone.NAME_UNASSIGNED : name, addr, BTTargetPhone.PORT_UNASSIGNED ); /*if (Util.isEmpty(new String(name))) { new SimpleQueue(false).execute(new Runnable() { public void run() { resolveFriendlyName(DeviceUpdate.NULL); result.setName(m_properties.get("name")); } }); }*/ // Set the port to unassigned and let it be discovered when scanning for OBEX. return result; } public void resolveFriendlyName(DeviceUpdate updater) { // Just set the name temporarily String name = "Querying device for name..."; m_properties.put( "name" , name); updater.deviceUpdated(this); try { name = m_device.getFriendlyName(false); // There seems to be a bug here: the first time // empty strings are returned from getFriendlyName(false)!? if (Util.isEmpty(name)) { name = m_device.getFriendlyName(true); } } catch (IOException e) { name = "Could not resolve device name"; } m_properties.put( "name", name); updater.deviceUpdated(this); } }