RemoteDevices.java revision c4b1ccb46884a0e23e5411f2bbb2da72fcb267ca
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; 27 28import com.android.bluetooth.Utils; 29 30import java.util.concurrent.atomic.AtomicInteger; 31import java.util.ArrayList; 32import java.util.HashMap; 33import java.util.LinkedList; 34import java.util.Queue; 35 36final class RemoteDevices { 37 private static final boolean DBG = false; 38 private static final String TAG = "BluetoothRemoteDevices"; 39 40 // Maximum number of device properties to remember 41 private static final int MAX_DEVICE_QUEUE_SIZE = 200; 42 43 private static BluetoothAdapter mAdapter; 44 private static AdapterService mAdapterService; 45 private static ArrayList<BluetoothDevice> mSdpTracker; 46 private Object mObject = new Object(); 47 48 private static final int UUID_INTENT_DELAY = 6000; 49 private static final int MESSAGE_UUID_INTENT = 1; 50 51 private HashMap<String, DeviceProperties> mDevices; 52 private Queue<String> mDeviceQueue; 53 54 RemoteDevices(AdapterService service) { 55 mAdapter = BluetoothAdapter.getDefaultAdapter(); 56 mAdapterService = service; 57 mSdpTracker = new ArrayList<BluetoothDevice>(); 58 mDevices = new HashMap<String, DeviceProperties>(); 59 mDeviceQueue = new LinkedList<String>(); 60 } 61 62 63 void cleanup() { 64 if (mSdpTracker !=null) 65 mSdpTracker.clear(); 66 67 if (mDevices != null) 68 mDevices.clear(); 69 70 if (mDeviceQueue != null) 71 mDeviceQueue.clear(); 72 } 73 74 @Override 75 public Object clone() throws CloneNotSupportedException { 76 throw new CloneNotSupportedException(); 77 } 78 79 DeviceProperties getDeviceProperties(BluetoothDevice device) { 80 synchronized (mDevices) { 81 return mDevices.get(device.getAddress()); 82 } 83 } 84 85 BluetoothDevice getDevice(byte[] address) { 86 DeviceProperties prop = mDevices.get(Utils.getAddressStringFromByte(address)); 87 if (prop == null) 88 return null; 89 return prop.getDevice(); 90 } 91 92 DeviceProperties addDeviceProperties(byte[] address) { 93 synchronized (mDevices) { 94 DeviceProperties prop = new DeviceProperties(); 95 prop.mDevice = mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address)); 96 prop.mAddress = address; 97 String key = Utils.getAddressStringFromByte(address); 98 DeviceProperties pv = mDevices.put(key, prop); 99 100 if (pv == null) { 101 mDeviceQueue.offer(key); 102 if (mDeviceQueue.size() > MAX_DEVICE_QUEUE_SIZE) { 103 String deleteKey = mDeviceQueue.poll(); 104 for (BluetoothDevice device : mAdapterService.getBondedDevices()) { 105 if (device.getAddress().equals(deleteKey)) return prop; 106 } 107 debugLog("Removing device " + deleteKey + " from property map"); 108 mDevices.remove(deleteKey); 109 } 110 } 111 return prop; 112 } 113 } 114 115 class DeviceProperties { 116 private String mName; 117 private byte[] mAddress; 118 private int mBluetoothClass; 119 private short mRssi; 120 private ParcelUuid[] mUuids; 121 private int mDeviceType; 122 private String mAlias; 123 private int mBondState; 124 private BluetoothDevice mDevice; 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 private void sendUuidIntent(BluetoothDevice device) { 245 DeviceProperties prop = getDeviceProperties(device); 246 Intent intent = new Intent(BluetoothDevice.ACTION_UUID); 247 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 248 intent.putExtra(BluetoothDevice.EXTRA_UUID, prop == null? null: prop.mUuids); 249 mAdapterService.initProfilePriorities(device, prop.mUuids); 250 mAdapterService.sendBroadcast(intent, AdapterService.BLUETOOTH_ADMIN_PERM); 251 252 //Remove the outstanding UUID request 253 mSdpTracker.remove(device); 254 } 255 256 257 void devicePropertyChangedCallback(byte[] address, int[] types, byte[][] values) { 258 Intent intent; 259 byte[] val; 260 int type; 261 BluetoothDevice bdDevice = getDevice(address); 262 DeviceProperties device; 263 if (bdDevice == null) { 264 debugLog("Added new device property"); 265 device = addDeviceProperties(address); 266 bdDevice = getDevice(address); 267 } else { 268 device = getDeviceProperties(bdDevice); 269 } 270 271 if (types.length <= 0) { 272 errorLog("No properties to update"); 273 return; 274 } 275 276 for (int j = 0; j < types.length; j++) { 277 type = types[j]; 278 val = values[j]; 279 if (val.length <= 0) 280 errorLog("devicePropertyChangedCallback: bdDevice: " + bdDevice 281 + ", value is empty for type: " + type); 282 else { 283 synchronized(mObject) { 284 debugLog("Property type: " + type); 285 switch (type) { 286 case AbstractionLayer.BT_PROPERTY_BDNAME: 287 device.mName = new String(val); 288 intent = new Intent(BluetoothDevice.ACTION_NAME_CHANGED); 289 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, bdDevice); 290 intent.putExtra(BluetoothDevice.EXTRA_NAME, device.mName); 291 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 292 mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM); 293 debugLog("Remote Device name is: " + device.mName); 294 break; 295 case AbstractionLayer.BT_PROPERTY_REMOTE_FRIENDLY_NAME: 296 if (device.mAlias != null) { 297 System.arraycopy(val, 0, device.mAlias, 0, val.length); 298 } 299 else { 300 device.mAlias = new String(val); 301 } 302 break; 303 case AbstractionLayer.BT_PROPERTY_BDADDR: 304 device.mAddress = val; 305 debugLog("Remote Address is:" + Utils.getAddressStringFromByte(val)); 306 break; 307 case AbstractionLayer.BT_PROPERTY_CLASS_OF_DEVICE: 308 device.mBluetoothClass = Utils.byteArrayToInt(val); 309 intent = new Intent(BluetoothDevice.ACTION_CLASS_CHANGED); 310 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, bdDevice); 311 intent.putExtra(BluetoothDevice.EXTRA_CLASS, 312 new BluetoothClass(device.mBluetoothClass)); 313 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 314 mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM); 315 debugLog("Remote class is:" + device.mBluetoothClass); 316 break; 317 case AbstractionLayer.BT_PROPERTY_UUIDS: 318 int numUuids = val.length/AbstractionLayer.BT_UUID_SIZE; 319 device.mUuids = Utils.byteArrayToUuid(val); 320 if (mAdapterService.getState() == BluetoothAdapter.STATE_ON) 321 sendUuidIntent(bdDevice); 322 break; 323 case AbstractionLayer.BT_PROPERTY_TYPE_OF_DEVICE: 324 // The device type from hal layer, defined in bluetooth.h, 325 // matches the type defined in BluetoothDevice.java 326 device.mDeviceType = Utils.byteArrayToInt(val); 327 break; 328 case AbstractionLayer.BT_PROPERTY_REMOTE_RSSI: 329 // RSSI from hal is in one byte 330 device.mRssi = val[0]; 331 break; 332 } 333 } 334 } 335 } 336 } 337 338 void deviceFoundCallback(byte[] address) { 339 // The device properties are already registered - we can send the intent 340 // now 341 BluetoothDevice device = getDevice(address); 342 debugLog("deviceFoundCallback: Remote Address is:" + device); 343 DeviceProperties deviceProp = getDeviceProperties(device); 344 if (deviceProp == null) { 345 errorLog("Device Properties is null for Device:" + device); 346 return; 347 } 348 349 Intent intent = new Intent(BluetoothDevice.ACTION_FOUND); 350 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 351 intent.putExtra(BluetoothDevice.EXTRA_CLASS, 352 new BluetoothClass(deviceProp.mBluetoothClass)); 353 intent.putExtra(BluetoothDevice.EXTRA_RSSI, deviceProp.mRssi); 354 intent.putExtra(BluetoothDevice.EXTRA_NAME, deviceProp.mName); 355 356 mAdapterService.sendBroadcastMultiplePermissions(intent, 357 new String[] {AdapterService.BLUETOOTH_PERM, 358 android.Manifest.permission.ACCESS_COARSE_LOCATION}); 359 } 360 361 void aclStateChangeCallback(int status, byte[] address, int newState) { 362 BluetoothDevice device = getDevice(address); 363 364 if (device == null) { 365 errorLog("aclStateChangeCallback: Device is NULL"); 366 return; 367 } 368 int state = mAdapterService.getState(); 369 Log.e(TAG, "state" + state + "newState" + newState); 370 371 DeviceProperties prop = getDeviceProperties(device); 372 if (prop == null) { 373 // errorLog("aclStateChangeCallback reported unknown device " + Arrays.toString(address)); 374 } 375 Intent intent = null; 376 if (newState == AbstractionLayer.BT_ACL_STATE_CONNECTED) { 377 if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_TURNING_ON) { 378 intent = new Intent(BluetoothDevice.ACTION_ACL_CONNECTED); 379 } else if (state == BluetoothAdapter.STATE_BLE_ON || state == BluetoothAdapter.STATE_BLE_TURNING_ON) { 380 intent = new Intent(BluetoothAdapter.ACTION_BLE_ACL_CONNECTED); 381 } 382 debugLog("aclStateChangeCallback: State:Connected to Device:" + device); 383 } else { 384 if (device.getBondState() == BluetoothDevice.BOND_BONDING) { 385 /*Broadcasting PAIRING_CANCEL intent as well in this case*/ 386 intent = new Intent(BluetoothDevice.ACTION_PAIRING_CANCEL); 387 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 388 mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM); 389 } 390 if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_TURNING_OFF) { 391 intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECTED); 392 } else if (state == BluetoothAdapter.STATE_BLE_ON || state == BluetoothAdapter.STATE_BLE_TURNING_OFF) { 393 intent = new Intent(BluetoothAdapter.ACTION_BLE_ACL_DISCONNECTED); 394 } 395 debugLog("aclStateChangeCallback: State:DisConnected to Device:" + device); 396 } 397 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 398 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 399 mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM); 400 } 401 402 403 void fetchUuids(BluetoothDevice device) { 404 if (mSdpTracker.contains(device)) return; 405 mSdpTracker.add(device); 406 407 Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT); 408 message.obj = device; 409 mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY); 410 411 mAdapterService.getRemoteServicesNative(Utils.getBytesFromAddress(device.getAddress())); 412 } 413 414 void updateUuids(BluetoothDevice device) { 415 Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT); 416 message.obj = device; 417 mHandler.sendMessage(message); 418 } 419 420 private final Handler mHandler = new Handler() { 421 @Override 422 public void handleMessage(Message msg) { 423 switch (msg.what) { 424 case MESSAGE_UUID_INTENT: 425 BluetoothDevice device = (BluetoothDevice)msg.obj; 426 if (device != null) { 427 sendUuidIntent(device); 428 } 429 break; 430 } 431 } 432 }; 433 434 private void errorLog(String msg) { 435 Log.e(TAG, msg); 436 } 437 438 private void debugLog(String msg) { 439 if (DBG) Log.d(TAG, msg); 440 } 441 442 private void infoLog(String msg) { 443 if (DBG) Log.i(TAG, msg); 444 } 445 446 private void warnLog(String msg) { 447 Log.w(TAG, msg); 448 } 449 450} 451