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