RemoteDevices.java revision 2c0df0560ad5ae3fd6022b17b17a6a70143e216a
1/* 2 * Copyright (C) 2012-2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.bluetooth.btservice; 18 19import android.bluetooth.BluetoothAdapter; 20import android.bluetooth.BluetoothClass; 21import android.bluetooth.BluetoothDevice; 22import android.bluetooth.BluetoothMasInstance; 23import android.content.Context; 24import android.content.Intent; 25import android.os.Handler; 26import android.os.Message; 27import android.os.ParcelUuid; 28import android.util.Log; 29 30import com.android.bluetooth.Utils; 31import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties; 32 33import java.util.concurrent.atomic.AtomicInteger; 34import java.util.ArrayList; 35import java.util.Arrays; 36import java.util.HashMap; 37import java.util.LinkedList; 38 39 40final class RemoteDevices { 41 private static final boolean DBG = false; 42 private static final String TAG = "BluetoothRemoteDevices"; 43 44 45 private static BluetoothAdapter mAdapter; 46 private static AdapterService mAdapterService; 47 private static ArrayList<BluetoothDevice> mSdpTracker; 48 private static ArrayList<BluetoothDevice> mSdpMasTracker; 49 50 private Object mObject = new Object(); 51 52 private static final int UUID_INTENT_DELAY = 6000; 53 private static final int MESSAGE_UUID_INTENT = 1; 54 55 private static final int MAS_INSTANCE_INTENT_DELAY = 6000; 56 private static final int MESSAGE_MAS_INSTANCE_INTENT = 2; 57 58 private HashMap<BluetoothDevice, DeviceProperties> mDevices; 59 60 RemoteDevices(AdapterService service) { 61 mAdapter = BluetoothAdapter.getDefaultAdapter(); 62 mAdapterService = service; 63 mSdpTracker = new ArrayList<BluetoothDevice>(); 64 mSdpMasTracker = new ArrayList<BluetoothDevice>(); 65 mDevices = new HashMap<BluetoothDevice, DeviceProperties>(); 66 } 67 68 69 void cleanup() { 70 if (mSdpTracker !=null) 71 mSdpTracker.clear(); 72 73 if (mSdpMasTracker != null) 74 mSdpMasTracker.clear(); 75 76 if (mDevices != null) 77 mDevices.clear(); 78 } 79 80 public Object Clone() throws CloneNotSupportedException { 81 throw new CloneNotSupportedException(); 82 } 83 84 DeviceProperties getDeviceProperties(BluetoothDevice device) { 85 synchronized (mDevices) { 86 return mDevices.get(device); 87 } 88 } 89 90 BluetoothDevice getDevice(byte[] address) { 91 for (BluetoothDevice dev : mDevices.keySet()) { 92 if (dev.getAddress().equals(Utils.getAddressStringFromByte(address))) { 93 return dev; 94 } 95 } 96 return null; 97 } 98 99 DeviceProperties addDeviceProperties(byte[] address) { 100 synchronized (mDevices) { 101 DeviceProperties prop = new DeviceProperties(); 102 BluetoothDevice device = 103 mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address)); 104 prop.mAddress = address; 105 mDevices.put(device, prop); 106 return prop; 107 } 108 } 109 110 class DeviceProperties { 111 private String mName; 112 private byte[] mAddress; 113 private int mBluetoothClass; 114 private short mRssi; 115 private ParcelUuid[] mUuids; 116 private int mDeviceType; 117 private String mAlias; 118 private int mBondState; 119 120 DeviceProperties() { 121 mBondState = BluetoothDevice.BOND_NONE; 122 } 123 124 /** 125 * @return the mName 126 */ 127 String getName() { 128 synchronized (mObject) { 129 return mName; 130 } 131 } 132 133 /** 134 * @return the mClass 135 */ 136 int getBluetoothClass() { 137 synchronized (mObject) { 138 return mBluetoothClass; 139 } 140 } 141 142 /** 143 * @return the mUuids 144 */ 145 ParcelUuid[] getUuids() { 146 synchronized (mObject) { 147 return mUuids; 148 } 149 } 150 151 /** 152 * @return the mAddress 153 */ 154 byte[] getAddress() { 155 synchronized (mObject) { 156 return mAddress; 157 } 158 } 159 160 /** 161 * @return mRssi 162 */ 163 short getRssi() { 164 synchronized (mObject) { 165 return mRssi; 166 } 167 } 168 169 /** 170 * @return mDeviceType 171 */ 172 int getDeviceType() { 173 synchronized (mObject) { 174 return mDeviceType; 175 } 176 } 177 178 /** 179 * @return the mAlias 180 */ 181 String getAlias() { 182 synchronized (mObject) { 183 return mAlias; 184 } 185 } 186 187 /** 188 * @param mAlias the mAlias to set 189 */ 190 void setAlias(String mAlias) { 191 synchronized (mObject) { 192 mAdapterService.setDevicePropertyNative(mAddress, 193 AbstractionLayer.BT_PROPERTY_REMOTE_FRIENDLY_NAME, mAlias.getBytes()); 194 } 195 } 196 197 /** 198 * @param mBondState the mBondState to set 199 */ 200 void setBondState(int mBondState) { 201 synchronized (mObject) { 202 this.mBondState = mBondState; 203 if (mBondState == BluetoothDevice.BOND_NONE) 204 { 205 /* Clearing the Uuids local copy when the device is unpaired. If not cleared, 206 cachedBluetoothDevice issued a connect using the local cached copy of uuids, 207 without waiting for the ACTION_UUID intent. 208 This was resulting in multiple calls to connect().*/ 209 mUuids = null; 210 } 211 } 212 } 213 214 /** 215 * @return the mBondState 216 */ 217 int getBondState() { 218 synchronized (mObject) { 219 return mBondState; 220 } 221 } 222 } 223 224 private void sendUuidIntent(BluetoothDevice device) { 225 DeviceProperties prop = getDeviceProperties(device); 226 Intent intent = new Intent(BluetoothDevice.ACTION_UUID); 227 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 228 intent.putExtra(BluetoothDevice.EXTRA_UUID, prop == null? null: prop.mUuids); 229 mAdapterService.initProfilePriorities(device, prop.mUuids); 230 mAdapterService.sendBroadcast(intent, AdapterService.BLUETOOTH_ADMIN_PERM); 231 232 //Remove the outstanding UUID request 233 mSdpTracker.remove(device); 234 } 235 236 private void sendMasInstanceIntent(BluetoothDevice device, 237 ArrayList<BluetoothMasInstance> instances) { 238 Intent intent = new Intent(BluetoothDevice.ACTION_MAS_INSTANCE); 239 240 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 241 if (instances != null) intent.putExtra(BluetoothDevice.EXTRA_MAS_INSTANCE, instances); 242 mAdapterService.sendBroadcast(intent, AdapterService.BLUETOOTH_ADMIN_PERM); 243 244 //Remove the outstanding UUID request 245 mSdpMasTracker.remove(device); 246 } 247 248 private void sendDisplayPinIntent(byte[] address, int pin) { 249 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST); 250 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, getDevice(address)); 251 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, pin); 252 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, 253 BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN); 254 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 255 mAdapterService.sendOrderedBroadcast(intent, mAdapterService.BLUETOOTH_ADMIN_PERM); 256 } 257 258 void devicePropertyChangedCallback(byte[] address, int[] types, byte[][] values) { 259 Intent intent; 260 byte[] val; 261 int type; 262 BluetoothDevice bdDevice = getDevice(address); 263 DeviceProperties device; 264 if (bdDevice == null) { 265 device = addDeviceProperties(address); 266 bdDevice = getDevice(address); 267 } else { 268 device = getDeviceProperties(bdDevice); 269 } 270 271 for (int j = 0; j < types.length; j++) { 272 type = types[j]; 273 val = values[j]; 274 if(val.length <= 0) 275 errorLog("devicePropertyChangedCallback: bdDevice: " + bdDevice + ", value is empty for type: " + type); 276 else { 277 synchronized(mObject) { 278 switch (type) { 279 case AbstractionLayer.BT_PROPERTY_BDNAME: 280 device.mName = new String(val); 281 intent = new Intent(BluetoothDevice.ACTION_NAME_CHANGED); 282 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, bdDevice); 283 intent.putExtra(BluetoothDevice.EXTRA_NAME, device.mName); 284 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 285 mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM); 286 debugLog("Remote Device name is: " + device.mName); 287 break; 288 case AbstractionLayer.BT_PROPERTY_REMOTE_FRIENDLY_NAME: 289 if (device.mAlias != null) { 290 System.arraycopy(val, 0, device.mAlias, 0, val.length); 291 } 292 else { 293 device.mAlias = new String(val); 294 } 295 break; 296 case AbstractionLayer.BT_PROPERTY_BDADDR: 297 device.mAddress = val; 298 debugLog("Remote Address is:" + Utils.getAddressStringFromByte(val)); 299 break; 300 case AbstractionLayer.BT_PROPERTY_CLASS_OF_DEVICE: 301 device.mBluetoothClass = Utils.byteArrayToInt(val); 302 intent = new Intent(BluetoothDevice.ACTION_CLASS_CHANGED); 303 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, bdDevice); 304 intent.putExtra(BluetoothDevice.EXTRA_CLASS, 305 new BluetoothClass(device.mBluetoothClass)); 306 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 307 mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM); 308 debugLog("Remote class is:" + device.mBluetoothClass); 309 break; 310 case AbstractionLayer.BT_PROPERTY_UUIDS: 311 int numUuids = val.length/AbstractionLayer.BT_UUID_SIZE; 312 device.mUuids = Utils.byteArrayToUuid(val); 313 sendUuidIntent(bdDevice); 314 break; 315 case AbstractionLayer.BT_PROPERTY_TYPE_OF_DEVICE: 316 // The device type from hal layer, defined in bluetooth.h, 317 // matches the type defined in BluetoothDevice.java 318 device.mDeviceType = Utils.byteArrayToInt(val); 319 break; 320 case AbstractionLayer.BT_PROPERTY_REMOTE_RSSI: 321 // RSSI from hal is in one byte 322 device.mRssi = val[0]; 323 break; 324 } 325 } 326 } 327 } 328 } 329 330 void deviceFoundCallback(byte[] address) { 331 // The device properties are already registered - we can send the intent 332 // now 333 BluetoothDevice device = getDevice(address); 334 debugLog("deviceFoundCallback: Remote Address is:" + device); 335 DeviceProperties deviceProp = getDeviceProperties(device); 336 if (deviceProp == null) { 337 errorLog("Device Properties is null for Device:" + device); 338 return; 339 } 340 341 Intent intent = new Intent(BluetoothDevice.ACTION_FOUND); 342 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 343 intent.putExtra(BluetoothDevice.EXTRA_CLASS, 344 new BluetoothClass(Integer.valueOf(deviceProp.mBluetoothClass))); 345 intent.putExtra(BluetoothDevice.EXTRA_RSSI, deviceProp.mRssi); 346 intent.putExtra(BluetoothDevice.EXTRA_NAME, deviceProp.mName); 347 348 mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM); 349 } 350 351 void pinRequestCallback(byte[] address, byte[] name, int cod) { 352 //TODO(BT): Get wakelock and update name and cod 353 BluetoothDevice bdDevice = getDevice(address); 354 if (bdDevice == null) { 355 addDeviceProperties(address); 356 } 357 BluetoothClass btClass = bdDevice.getBluetoothClass(); 358 int btDeviceClass = btClass.getDeviceClass(); 359 if (btDeviceClass == BluetoothClass.Device.PERIPHERAL_KEYBOARD || 360 btDeviceClass == BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING) { 361 // Its a keyboard. Follow the HID spec recommendation of creating the 362 // passkey and displaying it to the user. If the keyboard doesn't follow 363 // the spec recommendation, check if the keyboard has a fixed PIN zero 364 // and pair. 365 //TODO: Add sFixedPinZerosAutoPairKeyboard() and maintain list of devices that have fixed pin 366 /*if (mAdapterService.isFixedPinZerosAutoPairKeyboard(address)) { 367 mAdapterService.setPin(address, BluetoothDevice.convertPinToBytes("0000")); 368 return; 369 }*/ 370 // Generate a variable PIN. This is not truly random but good enough. 371 int pin = (int) Math.floor(Math.random() * 1000000); 372 sendDisplayPinIntent(address, pin); 373 return; 374 } 375 infoLog("pinRequestCallback: " + address + " name:" + name + " cod:" + 376 cod); 377 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST); 378 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, getDevice(address)); 379 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, 380 BluetoothDevice.PAIRING_VARIANT_PIN); 381 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 382 mAdapterService.sendOrderedBroadcast(intent, mAdapterService.BLUETOOTH_ADMIN_PERM); 383 return; 384 } 385 386 void sspRequestCallback(byte[] address, byte[] name, int cod, int pairingVariant, 387 int passkey) { 388 //TODO(BT): Get wakelock and update name and cod 389 BluetoothDevice bdDevice = getDevice(address); 390 if (bdDevice == null) { 391 addDeviceProperties(address); 392 } 393 394 infoLog("sspRequestCallback: " + address + " name: " + name + " cod: " + 395 cod + " pairingVariant " + pairingVariant + " passkey: " + passkey); 396 int variant; 397 boolean displayPasskey = false; 398 if (pairingVariant == AbstractionLayer.BT_SSP_VARIANT_PASSKEY_CONFIRMATION) { 399 variant = BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION; 400 displayPasskey = true; 401 } else if (pairingVariant == AbstractionLayer.BT_SSP_VARIANT_CONSENT) { 402 variant = BluetoothDevice.PAIRING_VARIANT_CONSENT; 403 } else if (pairingVariant == AbstractionLayer.BT_SSP_VARIANT_PASSKEY_ENTRY) { 404 variant = BluetoothDevice.PAIRING_VARIANT_PASSKEY; 405 } else if (pairingVariant == AbstractionLayer.BT_SSP_VARIANT_PASSKEY_NOTIFICATION) { 406 variant = BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY; 407 displayPasskey = true; 408 } else { 409 errorLog("SSP Pairing variant not present"); 410 return; 411 } 412 BluetoothDevice device = getDevice(address); 413 if (device == null) { 414 warnLog("Device is not known for:" + Utils.getAddressStringFromByte(address)); 415 addDeviceProperties(address); 416 device = getDevice(address); 417 } 418 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST); 419 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 420 if (displayPasskey) { 421 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, passkey); 422 } 423 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, variant); 424 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 425 mAdapterService.sendOrderedBroadcast(intent, mAdapterService.BLUETOOTH_ADMIN_PERM); 426 } 427 428 void aclStateChangeCallback(int status, byte[] address, int newState) { 429 BluetoothDevice device = getDevice(address); 430 431 if (device == null) { 432 errorLog("aclStateChangeCallback: Device is NULL"); 433 return; 434 } 435 436 DeviceProperties prop = getDeviceProperties(device); 437 if (prop == null) { 438 errorLog("aclStateChangeCallback reported unknown device " + Arrays.toString(address)); 439 } 440 Intent intent = null; 441 if (newState == AbstractionLayer.BT_ACL_STATE_CONNECTED) { 442 intent = new Intent(BluetoothDevice.ACTION_ACL_CONNECTED); 443 debugLog("aclStateChangeCallback: State:Connected to Device:" + device); 444 } else { 445 intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECTED); 446 debugLog("aclStateChangeCallback: State:DisConnected to Device:" + device); 447 } 448 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 449 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 450 mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM); 451 } 452 453 void deviceMasInstancesFoundCallback(int status, byte[] address, String[] name, int[] scn, 454 int[] id, int[] msgtype) { 455 BluetoothDevice device = getDevice(address); 456 457 if (device == null) { 458 errorLog("deviceMasInstancesFoundCallback: Device is NULL"); 459 return; 460 } 461 462 debugLog("deviceMasInstancesFoundCallback: found " + name.length + " instances"); 463 464 ArrayList<BluetoothMasInstance> instances = new ArrayList<BluetoothMasInstance>(); 465 466 for (int i = 0; i < name.length; i++) { 467 BluetoothMasInstance inst = new BluetoothMasInstance(id[i], name[i], 468 scn[i], msgtype[i]); 469 470 debugLog(inst.toString()); 471 472 instances.add(inst); 473 } 474 475 sendMasInstanceIntent(device, instances); 476 } 477 478 void fetchUuids(BluetoothDevice device) { 479 if (mSdpTracker.contains(device)) return; 480 mSdpTracker.add(device); 481 482 Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT); 483 message.obj = device; 484 mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY); 485 486 //mAdapterService.getDevicePropertyNative(Utils.getBytesFromAddress(device.getAddress()), AbstractionLayer.BT_PROPERTY_UUIDS); 487 mAdapterService.getRemoteServicesNative(Utils.getBytesFromAddress(device.getAddress())); 488 } 489 490 void fetchMasInstances(BluetoothDevice device) { 491 if (mSdpMasTracker.contains(device)) return; 492 mSdpMasTracker.add(device); 493 494 Message message = mHandler.obtainMessage(MESSAGE_MAS_INSTANCE_INTENT); 495 message.obj = device; 496 mHandler.sendMessageDelayed(message, MAS_INSTANCE_INTENT_DELAY); 497 498 mAdapterService.getRemoteMasInstancesNative(Utils.getBytesFromAddress(device.getAddress())); 499 } 500 501 private final Handler mHandler = new Handler() { 502 @Override 503 public void handleMessage(Message msg) { 504 switch (msg.what) { 505 case MESSAGE_UUID_INTENT: 506 BluetoothDevice device = (BluetoothDevice)msg.obj; 507 if (device != null) { 508 sendUuidIntent(device); 509 } 510 break; 511 case MESSAGE_MAS_INSTANCE_INTENT: 512 BluetoothDevice dev = (BluetoothDevice)msg.obj; 513 if (dev != null) { 514 sendMasInstanceIntent(dev, null); 515 } 516 break; 517 } 518 } 519 }; 520 521 private void errorLog(String msg) { 522 Log.e(TAG, msg); 523 } 524 525 private void debugLog(String msg) { 526 if (DBG) Log.d(TAG, msg); 527 } 528 529 private void infoLog(String msg) { 530 if (DBG) Log.i(TAG, msg); 531 } 532 533 private void warnLog(String msg) { 534 Log.w(TAG, msg); 535 } 536 537} 538