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