RemoteDevices.java revision ff4f17bf64978d0738c66e1b6dd70be8664efc24
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 infoLog("pinRequestCallback: " + address + " name:" + name + " cod:" + 284 cod); 285 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST); 286 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, getDevice(address)); 287 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, 288 BluetoothDevice.PAIRING_VARIANT_PIN); 289 mContext.sendBroadcast(intent, mAdapterService.BLUETOOTH_ADMIN_PERM); 290 return; 291 } 292 293 void passkeyRequestCallback(byte[] address, byte[] name, int cod) { 294 //TODO(BT): Get wakelock and update name and cod 295 infoLog("passkeyRequestCallback: " + address + " name:" + name + " cod:" + 296 cod); 297 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST); 298 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, getDevice(address)); 299 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, 300 BluetoothDevice.PAIRING_VARIANT_PIN); 301 mContext.sendBroadcast(intent, mAdapterService.BLUETOOTH_ADMIN_PERM); 302 return; 303 } 304 305 void sspRequestCallback(byte[] address, byte[] name, int cod, int pairingVariant, 306 int passkey) { 307 //TODO(BT): Get wakelock and update name and cod 308 infoLog("sspRequestCallback: " + address + " name: " + name + " cod: " + 309 cod + " pairingVariant " + pairingVariant + " passkey: " + passkey); 310 int variant; 311 boolean displayPasskey = false; 312 if (pairingVariant == AbstractionLayer.BT_SSP_VARIANT_PASSKEY_CONFIRMATION) { 313 variant = BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION; 314 displayPasskey = true; 315 } else if (pairingVariant == AbstractionLayer.BT_SSP_VARIANT_CONSENT) { 316 //TODO(BT): This needs to be fixed in the HAL. They have it wrong. 317 variant = BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION; 318 displayPasskey = true; 319 } else if (pairingVariant == AbstractionLayer.BT_SSP_VARIANT_PASSKEY_ENTRY) { 320 variant = BluetoothDevice.PAIRING_VARIANT_PASSKEY; 321 } else { 322 errorLog("SSP Pairing variant not present"); 323 return; 324 } 325 BluetoothDevice device = getDevice(address); 326 if (device == null) { 327 warnLog("Device is not known for:" + Utils.getAddressStringFromByte(address)); 328 addDeviceProperties(address); 329 device = getDevice(address); 330 } 331 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST); 332 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 333 if (displayPasskey) { 334 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, passkey); 335 } 336 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, variant); 337 mContext.sendBroadcast(intent, mAdapterService.BLUETOOTH_ADMIN_PERM); 338 } 339 340 341 void performSdp(BluetoothDevice device) { 342 if (mSdpTracker.contains(device)) return; 343 mSdpTracker.add(device); 344 345 Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT); 346 message.obj = device; 347 mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY); 348 349 //TODO(BT) 350 //mAdapterService.performSdpNative(device.mAddress); 351 } 352 353 private final Handler mHandler = new Handler() { 354 @Override 355 public void handleMessage(Message msg) { 356 switch (msg.what) { 357 case MESSAGE_UUID_INTENT: 358 BluetoothDevice device = (BluetoothDevice)msg.obj; 359 if (device != null) { 360 sendUuidIntent(device); 361 } 362 break; 363 } 364 } 365 }; 366 367 private void errorLog(String msg) { 368 Log.e(TAG, msg); 369 } 370 371 private void debugLog(String msg) { 372 if (DBG) Log.e(TAG, msg); 373 } 374 375 private void infoLog(String msg) { 376 if (DBG) Log.i(TAG, msg); 377 } 378 379 private void warnLog(String msg) { 380 Log.w(TAG, msg); 381 } 382} 383