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