RemoteDevices.java revision 1444b5b09d07b1ad5ec2ce89b4267484be25e8bf
1/* 2 * Copyright (C) 2012 Google Inc. 3 */ 4 5package com.android.bluetooth.btservice; 6 7import android.bluetooth.BluetoothAdapter; 8import android.bluetooth.BluetoothClass; 9import android.bluetooth.BluetoothDevice; 10import android.content.Context; 11import android.content.Intent; 12import android.os.Handler; 13import android.os.Message; 14import android.os.ParcelUuid; 15import android.util.Log; 16 17import com.android.bluetooth.Utils; 18import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties; 19 20import java.util.ArrayList; 21import java.util.HashMap; 22import java.util.LinkedList; 23 24 25final class RemoteDevices { 26 private static final boolean DBG = true; 27 private static final String TAG = "BluetoothRemoteDevices"; 28 29 private static Context mContext; 30 private static BluetoothAdapter mAdapter; 31 private static AdapterService mAdapterService; 32 private static ArrayList<BluetoothDevice> mSdpTracker; 33 34 private Object mObject = new Object(); 35 36 private static final int UUID_INTENT_DELAY = 6000; 37 private static final int MESSAGE_UUID_INTENT = 1; 38 39 private HashMap<BluetoothDevice, DeviceProperties> mDevices; 40 private static RemoteDevices sInstance; 41 42 private RemoteDevices(AdapterService service, Context context) { 43 mAdapter = BluetoothAdapter.getDefaultAdapter(); 44 mAdapterService = service; 45 mSdpTracker = new ArrayList<BluetoothDevice>(); 46 mDevices = new HashMap<BluetoothDevice, DeviceProperties>(); 47 mContext = context; 48 } 49 50 static synchronized RemoteDevices getInstance(AdapterService service, Context context) { 51 if (sInstance == null) sInstance = new RemoteDevices(service, context); 52 return sInstance; 53 } 54 55 public Object Clone() throws CloneNotSupportedException { 56 throw new CloneNotSupportedException(); 57 } 58 59 DeviceProperties getDeviceProperties(BluetoothDevice device) { 60 synchronized (mDevices) { 61 return mDevices.get(device); 62 } 63 } 64 65 BluetoothDevice getDevice(byte[] address) { 66 for (BluetoothDevice dev : mDevices.keySet()) { 67 if (dev.getAddress().equals(Utils.getAddressStringFromByte(address))) { 68 return dev; 69 } 70 } 71 return null; 72 } 73 74 DeviceProperties addDeviceProperties(byte[] address) { 75 synchronized (mDevices) { 76 DeviceProperties prop = new DeviceProperties(); 77 BluetoothDevice device = 78 mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address)); 79 mDevices.put(device, prop); 80 return prop; 81 } 82 } 83 84 class DeviceProperties { 85 private String mName; 86 private byte[] mAddress; 87 private int mBluetoothClass; 88 private short mRssi; 89 private ParcelUuid[] mUuids; 90 private int mDeviceType; 91 private String mAlias; 92 private int mBondState; 93 94 DeviceProperties() { 95 mBondState = BluetoothDevice.BOND_NONE; 96 } 97 98 /** 99 * @return the mName 100 */ 101 String getName() { 102 synchronized (mObject) { 103 return mName; 104 } 105 } 106 107 /** 108 * @return the mClass 109 */ 110 int getBluetoothClass() { 111 synchronized (mObject) { 112 return mBluetoothClass; 113 } 114 } 115 116 /** 117 * @return the mUuids 118 */ 119 ParcelUuid[] getUuids() { 120 synchronized (mObject) { 121 return mUuids; 122 } 123 } 124 125 /** 126 * @return the mAddress 127 */ 128 byte[] getAddress() { 129 synchronized (mObject) { 130 return mAddress; 131 } 132 } 133 134 /** 135 * @return mRssi 136 */ 137 short getRssi() { 138 synchronized (mObject) { 139 return mRssi; 140 } 141 } 142 143 /** 144 * 145 * @return mDeviceType 146 */ 147 int getDeviceType() { 148 synchronized (mObject) { 149 return mDeviceType; 150 } 151 } 152 153 /** 154 * @return the mAlias 155 */ 156 String getAlias() { 157 synchronized (mObject) { 158 return mAlias; 159 } 160 } 161 162 /** 163 * @param mAlias the mAlias to set 164 */ 165 void setAlias(String mAlias) { 166 synchronized (mObject) { 167 mAdapterService.setDevicePropertyNative(mAddress, 168 AbstractionLayer.BT_PROPERTY_REMOTE_FRIENDLY_NAME, mAlias.getBytes()); 169 } 170 } 171 172 /** 173 * @param mBondState the mBondState to set 174 */ 175 void setBondState(int mBondState) { 176 synchronized (mObject) { 177 this.mBondState = mBondState; 178 } 179 } 180 181 /** 182 * @return the mBondState 183 */ 184 int getBondState() { 185 synchronized (mObject) { 186 return mBondState; 187 } 188 } 189 } 190 191 192 private void sendUuidIntent(BluetoothDevice device) { 193 DeviceProperties prop = getDeviceProperties(device); 194 Intent intent = new Intent(BluetoothDevice.ACTION_UUID); 195 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 196 intent.putExtra(BluetoothDevice.EXTRA_UUID, prop.mUuids); 197 mContext.sendBroadcast(intent, AdapterService.BLUETOOTH_ADMIN_PERM); 198 } 199 200 void devicePropertyChangedCallback(byte[] address, int[] types, byte[][] values) { 201 Intent intent; 202 byte[] val; 203 int type; 204 BluetoothDevice bdDevice = getDevice(address); 205 DeviceProperties device; 206 if (bdDevice == null) { 207 device = addDeviceProperties(address); 208 bdDevice = getDevice(address); 209 } else { 210 device = getDeviceProperties(bdDevice); 211 } 212 213 for (int j = 0; j < types.length; j++) { 214 type = types[j]; 215 val = values[j]; 216 synchronized(mObject) { 217 switch (type) { 218 case AbstractionLayer.BT_PROPERTY_BDNAME: 219 device.mName = new String(val); 220 intent = new Intent(BluetoothDevice.ACTION_NAME_CHANGED); 221 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, bdDevice); 222 intent.putExtra(BluetoothDevice.EXTRA_NAME, device.mName); 223 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 224 mContext.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM); 225 debugLog("Remote Device ame is: " + device.mName); 226 break; 227 case AbstractionLayer.BT_PROPERTY_REMOTE_FRIENDLY_NAME: 228 System.arraycopy(val, 0, device.mAlias, 0, val.length); 229 break; 230 case AbstractionLayer.BT_PROPERTY_BDADDR: 231 device.mAddress = val; 232 debugLog("Remote Address is:" + Utils.getAddressStringFromByte(val)); 233 break; 234 case AbstractionLayer.BT_PROPERTY_CLASS_OF_DEVICE: 235 device.mBluetoothClass = Utils.byteArrayToInt(val); 236 intent = new Intent(BluetoothDevice.ACTION_CLASS_CHANGED); 237 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, bdDevice); 238 intent.putExtra(BluetoothDevice.EXTRA_CLASS, 239 new BluetoothClass(device.mBluetoothClass)); 240 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 241 mContext.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM); 242 debugLog("Remote class is:" + device.mBluetoothClass); 243 break; 244 case AbstractionLayer.BT_PROPERTY_UUIDS: 245 int numUuids = val.length/AbstractionLayer.BT_UUID_SIZE; 246 device.mUuids = Utils.byteArrayToUuid(val); 247 sendUuidIntent(bdDevice); 248 break; 249 case AbstractionLayer.BT_PROPERTY_TYPE_OF_DEVICE: 250 device.mDeviceType = Utils.byteArrayToInt(val); 251 break; 252 case AbstractionLayer.BT_PROPERTY_REMOTE_RSSI: 253 device.mRssi = Utils.byteArrayToShort(val); 254 break; 255 } 256 } 257 } 258 } 259 260 void deviceFoundCallback(byte[] address) { 261 // The device properties are already registered - we can send the intent 262 // now 263 BluetoothDevice device = getDevice(address); 264 debugLog("deviceFoundCallback: Remote Address is:" + device); 265 DeviceProperties deviceProp = getDeviceProperties(device); 266 if (deviceProp == null) { 267 errorLog("Device Properties is null for Device:" + device); 268 return; 269 } 270 271 Intent intent = new Intent(BluetoothDevice.ACTION_FOUND); 272 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 273 intent.putExtra(BluetoothDevice.EXTRA_CLASS, 274 new BluetoothClass(Integer.valueOf(deviceProp.mBluetoothClass))); 275 intent.putExtra(BluetoothDevice.EXTRA_RSSI, deviceProp.mRssi); 276 intent.putExtra(BluetoothDevice.EXTRA_NAME, deviceProp.mName); 277 278 mContext.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM); 279 } 280 281 void pinRequestCallback(byte[] address, byte[] name, int cod) { 282 //TODO(BT): Get wakelock and update name and cod 283 BluetoothDevice bdDevice = getDevice(address); 284 if (bdDevice == null) { 285 addDeviceProperties(address); 286 } 287 infoLog("pinRequestCallback: " + address + " name:" + name + " cod:" + 288 cod); 289 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST); 290 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, getDevice(address)); 291 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, 292 BluetoothDevice.PAIRING_VARIANT_PIN); 293 mContext.sendBroadcast(intent, mAdapterService.BLUETOOTH_ADMIN_PERM); 294 return; 295 } 296 297 void sspRequestCallback(byte[] address, byte[] name, int cod, int pairingVariant, 298 int passkey) { 299 //TODO(BT): Get wakelock and update name and cod 300 BluetoothDevice bdDevice = getDevice(address); 301 if (bdDevice == null) { 302 addDeviceProperties(address); 303 } 304 305 infoLog("sspRequestCallback: " + address + " name: " + name + " cod: " + 306 cod + " pairingVariant " + pairingVariant + " passkey: " + passkey); 307 int variant; 308 boolean displayPasskey = false; 309 if (pairingVariant == AbstractionLayer.BT_SSP_VARIANT_PASSKEY_CONFIRMATION) { 310 variant = BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION; 311 displayPasskey = true; 312 } else if (pairingVariant == AbstractionLayer.BT_SSP_VARIANT_CONSENT) { 313 variant = BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION; 314 } else if (pairingVariant == AbstractionLayer.BT_SSP_VARIANT_PASSKEY_ENTRY) { 315 variant = BluetoothDevice.PAIRING_VARIANT_PASSKEY; 316 } else if (pairingVariant == AbstractionLayer.BT_SSP_VARIANT_PASSKEY_NOTIFICATION) { 317 variant = BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY; 318 displayPasskey = true; 319 } else { 320 errorLog("SSP Pairing variant not present"); 321 return; 322 } 323 BluetoothDevice device = getDevice(address); 324 if (device == null) { 325 warnLog("Device is not known for:" + Utils.getAddressStringFromByte(address)); 326 addDeviceProperties(address); 327 device = getDevice(address); 328 } 329 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST); 330 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 331 if (displayPasskey) { 332 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, passkey); 333 } 334 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, variant); 335 mContext.sendBroadcast(intent, mAdapterService.BLUETOOTH_ADMIN_PERM); 336 } 337 338 339 void performSdp(BluetoothDevice device) { 340 if (mSdpTracker.contains(device)) return; 341 mSdpTracker.add(device); 342 343 Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT); 344 message.obj = device; 345 mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY); 346 347 //TODO(BT) 348 //mAdapterService.performSdpNative(device.mAddress); 349 } 350 351 private final Handler mHandler = new Handler() { 352 @Override 353 public void handleMessage(Message msg) { 354 switch (msg.what) { 355 case MESSAGE_UUID_INTENT: 356 BluetoothDevice device = (BluetoothDevice)msg.obj; 357 if (device != null) { 358 sendUuidIntent(device); 359 } 360 break; 361 } 362 } 363 }; 364 365 private void errorLog(String msg) { 366 Log.e(TAG, msg); 367 } 368 369 private void debugLog(String msg) { 370 if (DBG) Log.e(TAG, msg); 371 } 372 373 private void infoLog(String msg) { 374 if (DBG) Log.i(TAG, msg); 375 } 376 377 private void warnLog(String msg) { 378 Log.w(TAG, msg); 379 } 380} 381