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