RemoteDevices.java revision fbdf4f223574f48f8f3db83ea88e063a7551f799
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.content.Intent; 23import android.os.Handler; 24import android.os.Message; 25import android.os.ParcelUuid; 26import android.util.Log; 27import com.android.bluetooth.Utils; 28import java.util.ArrayList; 29import java.util.HashMap; 30import java.util.LinkedList; 31import java.util.Queue; 32 33final class RemoteDevices { 34 private static final boolean DBG = false; 35 private static final String TAG = "BluetoothRemoteDevices"; 36 37 // Maximum number of device properties to remember 38 private static final int MAX_DEVICE_QUEUE_SIZE = 200; 39 40 private static BluetoothAdapter mAdapter; 41 private static AdapterService mAdapterService; 42 private static ArrayList<BluetoothDevice> mSdpTracker; 43 private Object mObject = new Object(); 44 45 private static final int UUID_INTENT_DELAY = 6000; 46 private static final int MESSAGE_UUID_INTENT = 1; 47 48 private static final String PAIRING_REQUEST_PACKAGE = "com.android.settings"; 49 50 private HashMap<String, DeviceProperties> mDevices; 51 private Queue<String> mDeviceQueue; 52 53 RemoteDevices(AdapterService service) { 54 mAdapter = BluetoothAdapter.getDefaultAdapter(); 55 mAdapterService = service; 56 mSdpTracker = new ArrayList<BluetoothDevice>(); 57 mDevices = new HashMap<String, DeviceProperties>(); 58 mDeviceQueue = new LinkedList<String>(); 59 } 60 61 62 void cleanup() { 63 if (mSdpTracker !=null) 64 mSdpTracker.clear(); 65 66 if (mDevices != null) 67 mDevices.clear(); 68 69 if (mDeviceQueue != null) 70 mDeviceQueue.clear(); 71 } 72 73 @Override 74 public Object clone() throws CloneNotSupportedException { 75 throw new CloneNotSupportedException(); 76 } 77 78 DeviceProperties getDeviceProperties(BluetoothDevice device) { 79 synchronized (mDevices) { 80 return mDevices.get(device.getAddress()); 81 } 82 } 83 84 BluetoothDevice getDevice(byte[] address) { 85 DeviceProperties prop = mDevices.get(Utils.getAddressStringFromByte(address)); 86 if (prop == null) 87 return null; 88 return prop.getDevice(); 89 } 90 91 DeviceProperties addDeviceProperties(byte[] address) { 92 synchronized (mDevices) { 93 DeviceProperties prop = new DeviceProperties(); 94 prop.mDevice = mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address)); 95 prop.mAddress = address; 96 String key = Utils.getAddressStringFromByte(address); 97 DeviceProperties pv = mDevices.put(key, prop); 98 99 if (pv == null) { 100 mDeviceQueue.offer(key); 101 if (mDeviceQueue.size() > MAX_DEVICE_QUEUE_SIZE) { 102 String deleteKey = mDeviceQueue.poll(); 103 for (BluetoothDevice device : mAdapterService.getBondedDevices()) { 104 if (device.getAddress().equals(deleteKey)) return prop; 105 } 106 debugLog("Removing device " + deleteKey + " from property map"); 107 mDevices.remove(deleteKey); 108 } 109 } 110 return prop; 111 } 112 } 113 114 class DeviceProperties { 115 private String mName; 116 private byte[] mAddress; 117 private int mBluetoothClass; 118 private short mRssi; 119 private ParcelUuid[] mUuids; 120 private int mDeviceType; 121 private String mAlias; 122 private int mBondState; 123 private BluetoothDevice mDevice; 124 private boolean isBondingInitiatedLocally; 125 126 DeviceProperties() { 127 mBondState = BluetoothDevice.BOND_NONE; 128 } 129 130 /** 131 * @return the mName 132 */ 133 String getName() { 134 synchronized (mObject) { 135 return mName; 136 } 137 } 138 139 /** 140 * @return the mClass 141 */ 142 int getBluetoothClass() { 143 synchronized (mObject) { 144 return mBluetoothClass; 145 } 146 } 147 148 /** 149 * @return the mUuids 150 */ 151 ParcelUuid[] getUuids() { 152 synchronized (mObject) { 153 return mUuids; 154 } 155 } 156 157 /** 158 * @return the mAddress 159 */ 160 byte[] getAddress() { 161 synchronized (mObject) { 162 return mAddress; 163 } 164 } 165 166 /** 167 * @return the mDevice 168 */ 169 BluetoothDevice getDevice() { 170 synchronized (mObject) { 171 return mDevice; 172 } 173 } 174 175 /** 176 * @return mRssi 177 */ 178 short getRssi() { 179 synchronized (mObject) { 180 return mRssi; 181 } 182 } 183 184 /** 185 * @return mDeviceType 186 */ 187 int getDeviceType() { 188 synchronized (mObject) { 189 return mDeviceType; 190 } 191 } 192 193 /** 194 * @return the mAlias 195 */ 196 String getAlias() { 197 synchronized (mObject) { 198 return mAlias; 199 } 200 } 201 202 /** 203 * @param mAlias the mAlias to set 204 */ 205 void setAlias(BluetoothDevice device, String mAlias) { 206 synchronized (mObject) { 207 this.mAlias = mAlias; 208 mAdapterService.setDevicePropertyNative(mAddress, 209 AbstractionLayer.BT_PROPERTY_REMOTE_FRIENDLY_NAME, mAlias.getBytes()); 210 Intent intent = new Intent(BluetoothDevice.ACTION_ALIAS_CHANGED); 211 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 212 intent.putExtra(BluetoothDevice.EXTRA_NAME, mAlias); 213 mAdapterService.sendBroadcast(intent, AdapterService.BLUETOOTH_PERM); 214 } 215 } 216 217 /** 218 * @param mBondState the mBondState to set 219 */ 220 void setBondState(int mBondState) { 221 synchronized (mObject) { 222 this.mBondState = mBondState; 223 if (mBondState == BluetoothDevice.BOND_NONE) 224 { 225 /* Clearing the Uuids local copy when the device is unpaired. If not cleared, 226 cachedBluetoothDevice issued a connect using the local cached copy of uuids, 227 without waiting for the ACTION_UUID intent. 228 This was resulting in multiple calls to connect().*/ 229 mUuids = null; 230 } 231 } 232 } 233 234 /** 235 * @return the mBondState 236 */ 237 int getBondState() { 238 synchronized (mObject) { 239 return mBondState; 240 } 241 } 242 243 /** 244 * @param isBondingInitiatedLocally wether bonding is initiated locally 245 */ 246 void setBondingInitiatedLocally(boolean isBondingInitiatedLocally) { 247 synchronized (mObject) { 248 this.isBondingInitiatedLocally = isBondingInitiatedLocally; 249 } 250 } 251 252 /** 253 * @return the isBondingInitiatedLocally 254 */ 255 boolean isBondingInitiatedLocally() { 256 synchronized (mObject) { 257 return isBondingInitiatedLocally; 258 } 259 } 260 } 261 262 private void sendUuidIntent(BluetoothDevice device) { 263 DeviceProperties prop = getDeviceProperties(device); 264 Intent intent = new Intent(BluetoothDevice.ACTION_UUID); 265 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 266 intent.putExtra(BluetoothDevice.EXTRA_UUID, prop == null ? null : prop.mUuids); 267 mAdapterService.sendBroadcast(intent, AdapterService.BLUETOOTH_ADMIN_PERM); 268 269 //Remove the outstanding UUID request 270 mSdpTracker.remove(device); 271 } 272 273 /** 274 * When bonding is initiated to remote device that we have never seen, i.e Out Of Band pairing, we 275 * must add device first before setting it's properties. This is a helper method for doing that. 276 */ 277 void setBondingInitiatedLocally(byte[] address) { 278 DeviceProperties properties; 279 280 BluetoothDevice device = getDevice(address); 281 if (device == null) { 282 properties = addDeviceProperties(address); 283 } else { 284 properties = getDeviceProperties(device); 285 } 286 287 properties.setBondingInitiatedLocally(true); 288 } 289 290 291 void devicePropertyChangedCallback(byte[] address, int[] types, byte[][] values) { 292 Intent intent; 293 byte[] val; 294 int type; 295 BluetoothDevice bdDevice = getDevice(address); 296 DeviceProperties device; 297 if (bdDevice == null) { 298 device = addDeviceProperties(address); 299 bdDevice = getDevice(address); 300 } else { 301 device = getDeviceProperties(bdDevice); 302 } 303 304 for (int j = 0; j < types.length; j++) { 305 type = types[j]; 306 val = values[j]; 307 if(val.length <= 0) 308 errorLog("devicePropertyChangedCallback: bdDevice: " + bdDevice 309 + ", value is empty for type: " + type); 310 else { 311 synchronized(mObject) { 312 switch (type) { 313 case AbstractionLayer.BT_PROPERTY_BDNAME: 314 device.mName = new String(val); 315 intent = new Intent(BluetoothDevice.ACTION_NAME_CHANGED); 316 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, bdDevice); 317 intent.putExtra(BluetoothDevice.EXTRA_NAME, device.mName); 318 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 319 mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM); 320 debugLog("Remote Device name is: " + device.mName); 321 break; 322 case AbstractionLayer.BT_PROPERTY_REMOTE_FRIENDLY_NAME: 323 if (device.mAlias != null) { 324 System.arraycopy(val, 0, device.mAlias, 0, val.length); 325 } 326 else { 327 device.mAlias = new String(val); 328 } 329 break; 330 case AbstractionLayer.BT_PROPERTY_BDADDR: 331 device.mAddress = val; 332 debugLog("Remote Address is:" + Utils.getAddressStringFromByte(val)); 333 break; 334 case AbstractionLayer.BT_PROPERTY_CLASS_OF_DEVICE: 335 device.mBluetoothClass = Utils.byteArrayToInt(val); 336 intent = new Intent(BluetoothDevice.ACTION_CLASS_CHANGED); 337 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, bdDevice); 338 intent.putExtra(BluetoothDevice.EXTRA_CLASS, 339 new BluetoothClass(device.mBluetoothClass)); 340 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 341 mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM); 342 debugLog("Remote class is:" + device.mBluetoothClass); 343 break; 344 case AbstractionLayer.BT_PROPERTY_UUIDS: 345 int numUuids = val.length/AbstractionLayer.BT_UUID_SIZE; 346 device.mUuids = Utils.byteArrayToUuid(val); 347 if (mAdapterService.getState() == BluetoothAdapter.STATE_ON) 348 sendUuidIntent(bdDevice); 349 break; 350 case AbstractionLayer.BT_PROPERTY_TYPE_OF_DEVICE: 351 // The device type from hal layer, defined in bluetooth.h, 352 // matches the type defined in BluetoothDevice.java 353 device.mDeviceType = Utils.byteArrayToInt(val); 354 break; 355 case AbstractionLayer.BT_PROPERTY_REMOTE_RSSI: 356 // RSSI from hal is in one byte 357 device.mRssi = val[0]; 358 break; 359 } 360 } 361 } 362 } 363 } 364 365 void deviceFoundCallback(byte[] address) { 366 // The device properties are already registered - we can send the intent 367 // now 368 BluetoothDevice device = getDevice(address); 369 debugLog("deviceFoundCallback: Remote Address is:" + device); 370 DeviceProperties deviceProp = getDeviceProperties(device); 371 if (deviceProp == null) { 372 errorLog("Device Properties is null for Device:" + device); 373 return; 374 } 375 376 Intent intent = new Intent(BluetoothDevice.ACTION_FOUND); 377 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 378 intent.putExtra(BluetoothDevice.EXTRA_CLASS, 379 new BluetoothClass(deviceProp.mBluetoothClass)); 380 intent.putExtra(BluetoothDevice.EXTRA_RSSI, deviceProp.mRssi); 381 intent.putExtra(BluetoothDevice.EXTRA_NAME, deviceProp.mName); 382 383 mAdapterService.sendBroadcastMultiplePermissions(intent, 384 new String[] {AdapterService.BLUETOOTH_PERM, 385 android.Manifest.permission.ACCESS_COARSE_LOCATION}); 386 } 387 388 void aclStateChangeCallback(int status, byte[] address, int newState) { 389 BluetoothDevice device = getDevice(address); 390 391 if (device == null) { 392 errorLog("aclStateChangeCallback: Device is NULL"); 393 return; 394 } 395 int state = mAdapterService.getState(); 396 Log.e(TAG, "state " + BluetoothAdapter.nameForState(state) + " newState " + newState); 397 398 Intent intent = null; 399 if (newState == AbstractionLayer.BT_ACL_STATE_CONNECTED) { 400 if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_TURNING_ON) { 401 intent = new Intent(BluetoothDevice.ACTION_ACL_CONNECTED); 402 } else if (state == BluetoothAdapter.STATE_BLE_ON || state == BluetoothAdapter.STATE_BLE_TURNING_ON) { 403 intent = new Intent(BluetoothAdapter.ACTION_BLE_ACL_CONNECTED); 404 } 405 debugLog("aclStateChangeCallback: Connected: " + device); 406 } else { 407 if (device.getBondState() == BluetoothDevice.BOND_BONDING) { 408 // Send PAIRING_CANCEL intent to dismiss any dialog requesting bonding. 409 intent = new Intent(BluetoothDevice.ACTION_PAIRING_CANCEL); 410 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 411 intent.setPackage(PAIRING_REQUEST_PACKAGE); 412 mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM); 413 } 414 if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_TURNING_OFF) { 415 intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECTED); 416 } else if (state == BluetoothAdapter.STATE_BLE_ON || state == BluetoothAdapter.STATE_BLE_TURNING_OFF) { 417 intent = new Intent(BluetoothAdapter.ACTION_BLE_ACL_DISCONNECTED); 418 } 419 debugLog("aclStateChangeCallback: Disconnected: " + device); 420 } 421 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 422 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 423 mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM); 424 } 425 426 427 void fetchUuids(BluetoothDevice device) { 428 if (mSdpTracker.contains(device)) return; 429 mSdpTracker.add(device); 430 431 Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT); 432 message.obj = device; 433 mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY); 434 435 mAdapterService.getRemoteServicesNative(Utils.getBytesFromAddress(device.getAddress())); 436 } 437 438 void updateUuids(BluetoothDevice device) { 439 Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT); 440 message.obj = device; 441 mHandler.sendMessage(message); 442 } 443 444 private final Handler mHandler = new Handler() { 445 @Override 446 public void handleMessage(Message msg) { 447 switch (msg.what) { 448 case MESSAGE_UUID_INTENT: 449 BluetoothDevice device = (BluetoothDevice)msg.obj; 450 if (device != null) { 451 sendUuidIntent(device); 452 } 453 break; 454 } 455 } 456 }; 457 458 private void errorLog(String msg) { 459 Log.e(TAG, msg); 460 } 461 462 private void debugLog(String msg) { 463 if (DBG) Log.d(TAG, msg); 464 } 465 466 private void infoLog(String msg) { 467 if (DBG) Log.i(TAG, msg); 468 } 469 470 private void warnLog(String msg) { 471 Log.w(TAG, msg); 472 } 473 474} 475