RemoteDevices.java revision 619e48d1c82ff9b0ef25dee9ef3c391c41a61a58
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; 33 34 35final class RemoteDevices { 36 private static final boolean DBG = false; 37 private static final String TAG = "BluetoothRemoteDevices"; 38 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 HashMap<String, DeviceProperties> mDevices; 49 50 RemoteDevices(AdapterService service) { 51 mAdapter = BluetoothAdapter.getDefaultAdapter(); 52 mAdapterService = service; 53 mSdpTracker = new ArrayList<BluetoothDevice>(); 54 mDevices = new HashMap<String, DeviceProperties>(); 55 } 56 57 58 void cleanup() { 59 if (mSdpTracker !=null) 60 mSdpTracker.clear(); 61 62 if (mDevices != null) 63 mDevices.clear(); 64 } 65 66 @Override 67 public Object clone() throws CloneNotSupportedException { 68 throw new CloneNotSupportedException(); 69 } 70 71 DeviceProperties getDeviceProperties(BluetoothDevice device) { 72 synchronized (mDevices) { 73 return mDevices.get(device.getAddress()); 74 } 75 } 76 77 BluetoothDevice getDevice(byte[] address) { 78 DeviceProperties prop = mDevices.get(Utils.getAddressStringFromByte(address)); 79 if (prop == null) 80 return null; 81 return prop.getDevice(); 82 } 83 84 DeviceProperties addDeviceProperties(byte[] address) { 85 synchronized (mDevices) { 86 DeviceProperties prop = new DeviceProperties(); 87 prop.mDevice = mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address)); 88 prop.mAddress = address; 89 mDevices.put(Utils.getAddressStringFromByte(address), 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 private BluetoothDevice mDevice; 104 105 DeviceProperties() { 106 mBondState = BluetoothDevice.BOND_NONE; 107 } 108 109 /** 110 * @return the mName 111 */ 112 String getName() { 113 synchronized (mObject) { 114 return mName; 115 } 116 } 117 118 /** 119 * @return the mClass 120 */ 121 int getBluetoothClass() { 122 synchronized (mObject) { 123 return mBluetoothClass; 124 } 125 } 126 127 /** 128 * @return the mUuids 129 */ 130 ParcelUuid[] getUuids() { 131 synchronized (mObject) { 132 return mUuids; 133 } 134 } 135 136 /** 137 * @return the mAddress 138 */ 139 byte[] getAddress() { 140 synchronized (mObject) { 141 return mAddress; 142 } 143 } 144 145 /** 146 * @return the mDevice 147 */ 148 BluetoothDevice getDevice() { 149 synchronized (mObject) { 150 return mDevice; 151 } 152 } 153 154 /** 155 * @return mRssi 156 */ 157 short getRssi() { 158 synchronized (mObject) { 159 return mRssi; 160 } 161 } 162 163 /** 164 * @return mDeviceType 165 */ 166 int getDeviceType() { 167 synchronized (mObject) { 168 return mDeviceType; 169 } 170 } 171 172 /** 173 * @return the mAlias 174 */ 175 String getAlias() { 176 synchronized (mObject) { 177 return mAlias; 178 } 179 } 180 181 /** 182 * @param mAlias the mAlias to set 183 */ 184 void setAlias(BluetoothDevice device, String mAlias) { 185 synchronized (mObject) { 186 this.mAlias = mAlias; 187 mAdapterService.setDevicePropertyNative(mAddress, 188 AbstractionLayer.BT_PROPERTY_REMOTE_FRIENDLY_NAME, mAlias.getBytes()); 189 Intent intent = new Intent(BluetoothDevice.ACTION_ALIAS_CHANGED); 190 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 191 intent.putExtra(BluetoothDevice.EXTRA_NAME, mAlias); 192 mAdapterService.sendBroadcast(intent, AdapterService.BLUETOOTH_PERM); 193 } 194 } 195 196 /** 197 * @param mBondState the mBondState to set 198 */ 199 void setBondState(int mBondState) { 200 synchronized (mObject) { 201 this.mBondState = mBondState; 202 if (mBondState == BluetoothDevice.BOND_NONE) 203 { 204 /* Clearing the Uuids local copy when the device is unpaired. If not cleared, 205 cachedBluetoothDevice issued a connect using the local cached copy of uuids, 206 without waiting for the ACTION_UUID intent. 207 This was resulting in multiple calls to connect().*/ 208 mUuids = null; 209 } 210 } 211 } 212 213 /** 214 * @return the mBondState 215 */ 216 int getBondState() { 217 synchronized (mObject) { 218 return mBondState; 219 } 220 } 221 } 222 223 private void sendUuidIntent(BluetoothDevice device) { 224 DeviceProperties prop = getDeviceProperties(device); 225 Intent intent = new Intent(BluetoothDevice.ACTION_UUID); 226 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 227 intent.putExtra(BluetoothDevice.EXTRA_UUID, prop == null? null: prop.mUuids); 228 mAdapterService.initProfilePriorities(device, prop.mUuids); 229 mAdapterService.sendBroadcast(intent, AdapterService.BLUETOOTH_ADMIN_PERM); 230 231 //Remove the outstanding UUID request 232 mSdpTracker.remove(device); 233 } 234 235 236 void devicePropertyChangedCallback(byte[] address, int[] types, byte[][] values) { 237 Intent intent; 238 byte[] val; 239 int type; 240 BluetoothDevice bdDevice = getDevice(address); 241 DeviceProperties device; 242 if (bdDevice == null) { 243 device = addDeviceProperties(address); 244 bdDevice = getDevice(address); 245 } else { 246 device = getDeviceProperties(bdDevice); 247 } 248 249 for (int j = 0; j < types.length; j++) { 250 type = types[j]; 251 val = values[j]; 252 if(val.length <= 0) 253 errorLog("devicePropertyChangedCallback: bdDevice: " + bdDevice 254 + ", value is empty for type: " + type); 255 else { 256 synchronized(mObject) { 257 switch (type) { 258 case AbstractionLayer.BT_PROPERTY_BDNAME: 259 device.mName = new String(val); 260 intent = new Intent(BluetoothDevice.ACTION_NAME_CHANGED); 261 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, bdDevice); 262 intent.putExtra(BluetoothDevice.EXTRA_NAME, device.mName); 263 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 264 mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM); 265 debugLog("Remote Device name is: " + device.mName); 266 break; 267 case AbstractionLayer.BT_PROPERTY_REMOTE_FRIENDLY_NAME: 268 if (device.mAlias != null) { 269 System.arraycopy(val, 0, device.mAlias, 0, val.length); 270 } 271 else { 272 device.mAlias = new String(val); 273 } 274 break; 275 case AbstractionLayer.BT_PROPERTY_BDADDR: 276 device.mAddress = val; 277 debugLog("Remote Address is:" + Utils.getAddressStringFromByte(val)); 278 break; 279 case AbstractionLayer.BT_PROPERTY_CLASS_OF_DEVICE: 280 device.mBluetoothClass = Utils.byteArrayToInt(val); 281 intent = new Intent(BluetoothDevice.ACTION_CLASS_CHANGED); 282 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, bdDevice); 283 intent.putExtra(BluetoothDevice.EXTRA_CLASS, 284 new BluetoothClass(device.mBluetoothClass)); 285 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 286 mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM); 287 debugLog("Remote class is:" + device.mBluetoothClass); 288 break; 289 case AbstractionLayer.BT_PROPERTY_UUIDS: 290 int numUuids = val.length/AbstractionLayer.BT_UUID_SIZE; 291 device.mUuids = Utils.byteArrayToUuid(val); 292 if (mAdapterService.getState() == BluetoothAdapter.STATE_ON) 293 sendUuidIntent(bdDevice); 294 break; 295 case AbstractionLayer.BT_PROPERTY_TYPE_OF_DEVICE: 296 // The device type from hal layer, defined in bluetooth.h, 297 // matches the type defined in BluetoothDevice.java 298 device.mDeviceType = Utils.byteArrayToInt(val); 299 break; 300 case AbstractionLayer.BT_PROPERTY_REMOTE_RSSI: 301 // RSSI from hal is in one byte 302 device.mRssi = val[0]; 303 break; 304 } 305 } 306 } 307 } 308 } 309 310 void deviceFoundCallback(byte[] address) { 311 // The device properties are already registered - we can send the intent 312 // now 313 BluetoothDevice device = getDevice(address); 314 debugLog("deviceFoundCallback: Remote Address is:" + device); 315 DeviceProperties deviceProp = getDeviceProperties(device); 316 if (deviceProp == null) { 317 errorLog("Device Properties is null for Device:" + device); 318 return; 319 } 320 321 Intent intent = new Intent(BluetoothDevice.ACTION_FOUND); 322 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 323 intent.putExtra(BluetoothDevice.EXTRA_CLASS, 324 new BluetoothClass(deviceProp.mBluetoothClass)); 325 intent.putExtra(BluetoothDevice.EXTRA_RSSI, deviceProp.mRssi); 326 intent.putExtra(BluetoothDevice.EXTRA_NAME, deviceProp.mName); 327 328 mAdapterService.sendBroadcastMultiplePermissions(intent, 329 new String[] {AdapterService.BLUETOOTH_PERM, 330 android.Manifest.permission.ACCESS_COARSE_LOCATION}); 331 } 332 333 void aclStateChangeCallback(int status, byte[] address, int newState) { 334 BluetoothDevice device = getDevice(address); 335 336 if (device == null) { 337 errorLog("aclStateChangeCallback: Device is NULL"); 338 return; 339 } 340 int state = mAdapterService.getState(); 341 Log.e(TAG, "state" + state + "newState" + newState); 342 343 DeviceProperties prop = getDeviceProperties(device); 344 if (prop == null) { 345 // errorLog("aclStateChangeCallback reported unknown device " + Arrays.toString(address)); 346 } 347 Intent intent = null; 348 if (newState == AbstractionLayer.BT_ACL_STATE_CONNECTED) { 349 if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_TURNING_ON) { 350 intent = new Intent(BluetoothDevice.ACTION_ACL_CONNECTED); 351 } else if (state == BluetoothAdapter.STATE_BLE_ON || state == BluetoothAdapter.STATE_BLE_TURNING_ON) { 352 intent = new Intent(BluetoothAdapter.ACTION_BLE_ACL_CONNECTED); 353 } 354 debugLog("aclStateChangeCallback: State:Connected to Device:" + device); 355 } else { 356 if (device.getBondState() == BluetoothDevice.BOND_BONDING) { 357 /*Broadcasting PAIRING_CANCEL intent as well in this case*/ 358 intent = new Intent(BluetoothDevice.ACTION_PAIRING_CANCEL); 359 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 360 mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM); 361 } 362 if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_TURNING_OFF) { 363 intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECTED); 364 } else if (state == BluetoothAdapter.STATE_BLE_ON || state == BluetoothAdapter.STATE_BLE_TURNING_OFF) { 365 intent = new Intent(BluetoothAdapter.ACTION_BLE_ACL_DISCONNECTED); 366 } 367 debugLog("aclStateChangeCallback: State:DisConnected to Device:" + device); 368 } 369 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 370 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 371 mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM); 372 } 373 374 375 void fetchUuids(BluetoothDevice device) { 376 if (mSdpTracker.contains(device)) return; 377 mSdpTracker.add(device); 378 379 Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT); 380 message.obj = device; 381 mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY); 382 383 mAdapterService.getRemoteServicesNative(Utils.getBytesFromAddress(device.getAddress())); 384 } 385 386 void updateUuids(BluetoothDevice device) { 387 Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT); 388 message.obj = device; 389 mHandler.sendMessage(message); 390 } 391 392 private final Handler mHandler = new Handler() { 393 @Override 394 public void handleMessage(Message msg) { 395 switch (msg.what) { 396 case MESSAGE_UUID_INTENT: 397 BluetoothDevice device = (BluetoothDevice)msg.obj; 398 if (device != null) { 399 sendUuidIntent(device); 400 } 401 break; 402 } 403 } 404 }; 405 406 private void errorLog(String msg) { 407 Log.e(TAG, msg); 408 } 409 410 private void debugLog(String msg) { 411 if (DBG) Log.d(TAG, msg); 412 } 413 414 private void infoLog(String msg) { 415 if (DBG) Log.i(TAG, msg); 416 } 417 418 private void warnLog(String msg) { 419 Log.w(TAG, msg); 420 } 421 422} 423