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