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 if (mAdapterService.getState() == BluetoothAdapter.STATE_ON) 286 sendUuidIntent(bdDevice); 287 break; 288 case AbstractionLayer.BT_PROPERTY_TYPE_OF_DEVICE: 289 // The device type from hal layer, defined in bluetooth.h, 290 // matches the type defined in BluetoothDevice.java 291 device.mDeviceType = Utils.byteArrayToInt(val); 292 break; 293 case AbstractionLayer.BT_PROPERTY_REMOTE_RSSI: 294 // RSSI from hal is in one byte 295 device.mRssi = val[0]; 296 break; 297 } 298 } 299 } 300 } 301 } 302 deviceFoundCallback(byte[] address)303 void deviceFoundCallback(byte[] address) { 304 // The device properties are already registered - we can send the intent 305 // now 306 BluetoothDevice device = getDevice(address); 307 debugLog("deviceFoundCallback: Remote Address is:" + device); 308 DeviceProperties deviceProp = getDeviceProperties(device); 309 if (deviceProp == null) { 310 errorLog("Device Properties is null for Device:" + device); 311 return; 312 } 313 314 Intent intent = new Intent(BluetoothDevice.ACTION_FOUND); 315 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 316 intent.putExtra(BluetoothDevice.EXTRA_CLASS, 317 new BluetoothClass(deviceProp.mBluetoothClass)); 318 intent.putExtra(BluetoothDevice.EXTRA_RSSI, deviceProp.mRssi); 319 intent.putExtra(BluetoothDevice.EXTRA_NAME, deviceProp.mName); 320 321 mAdapterService.sendBroadcastMultiplePermissions(intent, 322 new String[] {AdapterService.BLUETOOTH_PERM, 323 android.Manifest.permission.ACCESS_COARSE_LOCATION}); 324 } 325 aclStateChangeCallback(int status, byte[] address, int newState)326 void aclStateChangeCallback(int status, byte[] address, int newState) { 327 BluetoothDevice device = getDevice(address); 328 329 if (device == null) { 330 errorLog("aclStateChangeCallback: Device is NULL"); 331 return; 332 } 333 int state = mAdapterService.getState(); 334 Log.e(TAG, "state" + state + "newState" + newState); 335 336 DeviceProperties prop = getDeviceProperties(device); 337 if (prop == null) { 338 // errorLog("aclStateChangeCallback reported unknown device " + Arrays.toString(address)); 339 } 340 Intent intent = null; 341 if (newState == AbstractionLayer.BT_ACL_STATE_CONNECTED) { 342 if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_TURNING_ON) { 343 intent = new Intent(BluetoothDevice.ACTION_ACL_CONNECTED); 344 } else if (state == BluetoothAdapter.STATE_BLE_ON || state == BluetoothAdapter.STATE_BLE_TURNING_ON) { 345 intent = new Intent(BluetoothAdapter.ACTION_BLE_ACL_CONNECTED); 346 } 347 debugLog("aclStateChangeCallback: State:Connected to Device:" + device); 348 } else { 349 if (device.getBondState() == BluetoothDevice.BOND_BONDING) { 350 /*Broadcasting PAIRING_CANCEL intent as well in this case*/ 351 intent = new Intent(BluetoothDevice.ACTION_PAIRING_CANCEL); 352 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 353 mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM); 354 } 355 if (state == BluetoothAdapter.STATE_ON || state == BluetoothAdapter.STATE_TURNING_OFF) { 356 intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECTED); 357 } else if (state == BluetoothAdapter.STATE_BLE_ON || state == BluetoothAdapter.STATE_BLE_TURNING_OFF) { 358 intent = new Intent(BluetoothAdapter.ACTION_BLE_ACL_DISCONNECTED); 359 } 360 debugLog("aclStateChangeCallback: State:DisConnected to Device:" + device); 361 } 362 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 363 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 364 mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM); 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 updateUuids(BluetoothDevice device)379 void updateUuids(BluetoothDevice device) { 380 Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT); 381 message.obj = device; 382 mHandler.sendMessage(message); 383 } 384 385 private final Handler mHandler = new Handler() { 386 @Override 387 public void handleMessage(Message msg) { 388 switch (msg.what) { 389 case MESSAGE_UUID_INTENT: 390 BluetoothDevice device = (BluetoothDevice)msg.obj; 391 if (device != null) { 392 sendUuidIntent(device); 393 } 394 break; 395 } 396 } 397 }; 398 errorLog(String msg)399 private void errorLog(String msg) { 400 Log.e(TAG, msg); 401 } 402 debugLog(String msg)403 private void debugLog(String msg) { 404 if (DBG) Log.d(TAG, msg); 405 } 406 infoLog(String msg)407 private void infoLog(String msg) { 408 if (DBG) Log.i(TAG, msg); 409 } 410 warnLog(String msg)411 private void warnLog(String msg) { 412 Log.w(TAG, msg); 413 } 414 415 } 416