BluetoothEventLoop.java revision 10eac971b3a6e5f34a420dd68ebfa796553ad2b9
1/* 2 * Copyright (C) 2008 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 android.server; 18 19import android.bluetooth.BluetoothA2dp; 20import android.bluetooth.BluetoothAdapter; 21import android.bluetooth.BluetoothClass; 22import android.bluetooth.BluetoothDevice; 23import android.bluetooth.BluetoothUuid; 24import android.bluetooth.ParcelUuid; 25import android.content.Context; 26import android.content.Intent; 27import android.os.Handler; 28import android.os.Message; 29import android.util.Log; 30 31import java.util.HashMap; 32 33/** 34 * TODO: Move this to 35 * java/services/com/android/server/BluetoothEventLoop.java 36 * and make the contructor package private again. 37 * 38 * @hide 39 */ 40class BluetoothEventLoop { 41 private static final String TAG = "BluetoothEventLoop"; 42 private static final boolean DBG = false; 43 44 private int mNativeData; 45 private Thread mThread; 46 private boolean mStarted; 47 private boolean mInterrupted; 48 49 private final HashMap<String, Integer> mPasskeyAgentRequestData; 50 private final BluetoothService mBluetoothService; 51 private final BluetoothAdapter mAdapter; 52 private final Context mContext; 53 54 private static final int EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 1; 55 private static final int EVENT_RESTART_BLUETOOTH = 2; 56 private static final int EVENT_PAIRING_CONSENT_DELAYED_ACCEPT = 3; 57 58 // The time (in millisecs) to delay the pairing attempt after the first 59 // auto pairing attempt fails. We use an exponential delay with 60 // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the initial value and 61 // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the max value. 62 private static final long INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 3000; 63 private static final long MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 12000; 64 65 private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN; 66 private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; 67 68 private final Handler mHandler = new Handler() { 69 @Override 70 public void handleMessage(Message msg) { 71 String address = null; 72 switch (msg.what) { 73 case EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY: 74 address = (String)msg.obj; 75 if (address != null) { 76 mBluetoothService.createBond(address); 77 return; 78 } 79 break; 80 case EVENT_RESTART_BLUETOOTH: 81 mBluetoothService.restart(); 82 break; 83 case EVENT_PAIRING_CONSENT_DELAYED_ACCEPT: 84 address = (String)msg.obj; 85 if (address != null) { 86 mBluetoothService.setPairingConfirmation(address, true); 87 } 88 break; 89 } 90 } 91 }; 92 93 static { classInitNative(); } 94 private static native void classInitNative(); 95 96 /* pacakge */ BluetoothEventLoop(Context context, BluetoothAdapter adapter, 97 BluetoothService bluetoothService) { 98 mBluetoothService = bluetoothService; 99 mContext = context; 100 mPasskeyAgentRequestData = new HashMap(); 101 mAdapter = adapter; 102 initializeNativeDataNative(); 103 } 104 105 protected void finalize() throws Throwable { 106 try { 107 cleanupNativeDataNative(); 108 } finally { 109 super.finalize(); 110 } 111 } 112 113 /* package */ HashMap<String, Integer> getPasskeyAgentRequestData() { 114 return mPasskeyAgentRequestData; 115 } 116 117 /* package */ void start() { 118 119 if (!isEventLoopRunningNative()) { 120 if (DBG) log("Starting Event Loop thread"); 121 startEventLoopNative(); 122 } 123 } 124 125 public void stop() { 126 if (isEventLoopRunningNative()) { 127 if (DBG) log("Stopping Event Loop thread"); 128 stopEventLoopNative(); 129 } 130 } 131 132 public boolean isEventLoopRunning() { 133 return isEventLoopRunningNative(); 134 } 135 136 private void addDevice(String address, String[] properties) { 137 mBluetoothService.addRemoteDeviceProperties(address, properties); 138 String rssi = mBluetoothService.getRemoteDeviceProperty(address, "RSSI"); 139 String classValue = mBluetoothService.getRemoteDeviceProperty(address, "Class"); 140 String name = mBluetoothService.getRemoteDeviceProperty(address, "Name"); 141 short rssiValue; 142 // For incoming connections, we don't get the RSSI value. Use a default of MIN_VALUE. 143 // If we accept the pairing, we will automatically show it at the top of the list. 144 if (rssi != null) { 145 rssiValue = (short)Integer.valueOf(rssi).intValue(); 146 } else { 147 rssiValue = Short.MIN_VALUE; 148 } 149 if (classValue != null) { 150 Intent intent = new Intent(BluetoothDevice.ACTION_FOUND); 151 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address)); 152 intent.putExtra(BluetoothDevice.EXTRA_CLASS, 153 new BluetoothClass(Integer.valueOf(classValue))); 154 intent.putExtra(BluetoothDevice.EXTRA_RSSI, rssiValue); 155 intent.putExtra(BluetoothDevice.EXTRA_NAME, name); 156 157 mContext.sendBroadcast(intent, BLUETOOTH_PERM); 158 } else { 159 log ("ClassValue: " + classValue + " for remote device: " + address + " is null"); 160 } 161 } 162 163 private void onDeviceFound(String address, String[] properties) { 164 if (properties == null) { 165 Log.e(TAG, "ERROR: Remote device properties are null"); 166 return; 167 } 168 addDevice(address, properties); 169 } 170 171 private void onDeviceDisappeared(String address) { 172 Intent intent = new Intent(BluetoothDevice.ACTION_DISAPPEARED); 173 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address)); 174 mContext.sendBroadcast(intent, BLUETOOTH_PERM); 175 } 176 177 private void onDeviceDisconnectRequested(String deviceObjectPath) { 178 String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath); 179 if (address == null) { 180 Log.e(TAG, "onDeviceDisconnectRequested: Address of the remote device in null"); 181 return; 182 } 183 Intent intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED); 184 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address)); 185 mContext.sendBroadcast(intent, BLUETOOTH_PERM); 186 } 187 188 private void onCreatePairedDeviceResult(String address, int result) { 189 address = address.toUpperCase(); 190 if (result == BluetoothDevice.BOND_SUCCESS) { 191 mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDED); 192 if (mBluetoothService.getBondState().isAutoPairingAttemptsInProgress(address)) { 193 mBluetoothService.getBondState().clearPinAttempts(address); 194 } 195 } else if (result == BluetoothDevice.UNBOND_REASON_AUTH_FAILED && 196 mBluetoothService.getBondState().getAttempt(address) == 1) { 197 mBluetoothService.getBondState().addAutoPairingFailure(address); 198 pairingAttempt(address, result); 199 } else if (result == BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN && 200 mBluetoothService.getBondState().isAutoPairingAttemptsInProgress(address)) { 201 pairingAttempt(address, result); 202 } else { 203 mBluetoothService.getBondState().setBondState(address, 204 BluetoothDevice.BOND_NONE, result); 205 if (mBluetoothService.getBondState().isAutoPairingAttemptsInProgress(address)) { 206 mBluetoothService.getBondState().clearPinAttempts(address); 207 } 208 } 209 } 210 211 private void pairingAttempt(String address, int result) { 212 // This happens when our initial guess of "0000" as the pass key 213 // fails. Try to create the bond again and display the pin dialog 214 // to the user. Use back-off while posting the delayed 215 // message. The initial value is 216 // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY and the max value is 217 // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY. If the max value is 218 // reached, display an error to the user. 219 int attempt = mBluetoothService.getBondState().getAttempt(address); 220 if (attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY > 221 MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY) { 222 mBluetoothService.getBondState().clearPinAttempts(address); 223 mBluetoothService.getBondState().setBondState(address, 224 BluetoothDevice.BOND_NONE, result); 225 return; 226 } 227 228 Message message = mHandler.obtainMessage(EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY); 229 message.obj = address; 230 boolean postResult = mHandler.sendMessageDelayed(message, 231 attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY); 232 if (!postResult) { 233 mBluetoothService.getBondState().clearPinAttempts(address); 234 mBluetoothService.getBondState().setBondState(address, 235 BluetoothDevice.BOND_NONE, result); 236 return; 237 } 238 mBluetoothService.getBondState().attempt(address); 239 } 240 241 private void onDeviceCreated(String deviceObjectPath) { 242 String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath); 243 if (!mBluetoothService.isRemoteDeviceInCache(address)) { 244 // Incoming connection, we haven't seen this device, add to cache. 245 String[] properties = mBluetoothService.getRemoteDeviceProperties(address); 246 if (properties != null) { 247 addDevice(address, properties); 248 } 249 } 250 mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDING); 251 return; 252 } 253 254 private void onDeviceRemoved(String deviceObjectPath) { 255 String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath); 256 if (address != null) 257 mBluetoothService.getBondState().setBondState(address.toUpperCase(), 258 BluetoothDevice.BOND_NONE, BluetoothDevice.UNBOND_REASON_REMOVED); 259 } 260 261 /*package*/ void onPropertyChanged(String[] propValues) { 262 if (mBluetoothService.isAdapterPropertiesEmpty()) { 263 // We have got a property change before 264 // we filled up our cache. 265 mBluetoothService.getAllProperties(); 266 } 267 String name = propValues[0]; 268 if (name.equals("Name")) { 269 Intent intent = new Intent(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED); 270 intent.putExtra(BluetoothAdapter.EXTRA_LOCAL_NAME, propValues[1]); 271 mContext.sendBroadcast(intent, BLUETOOTH_PERM); 272 mBluetoothService.setProperty(name, propValues[1]); 273 } else if (name.equals("Pairable") || name.equals("Discoverable")) { 274 String pairable = name.equals("Pairable") ? propValues[1] : 275 mBluetoothService.getProperty("Pairable"); 276 String discoverable = name.equals("Discoverable") ? propValues[1] : 277 mBluetoothService.getProperty("Discoverable"); 278 279 // This shouldn't happen, unless Adapter Properties are null. 280 if (pairable == null || discoverable == null) 281 return; 282 283 int mode = BluetoothService.bluezStringToScanMode( 284 pairable.equals("true"), 285 discoverable.equals("true")); 286 if (mode >= 0) { 287 Intent intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED); 288 intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, mode); 289 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 290 mContext.sendBroadcast(intent, BLUETOOTH_PERM); 291 } 292 mBluetoothService.setProperty(name, propValues[1]); 293 } else if (name.equals("Discovering")) { 294 Intent intent; 295 if (propValues[1].equals("true")) { 296 mBluetoothService.setIsDiscovering(true); 297 intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_STARTED); 298 } else { 299 // Stop the discovery. 300 mBluetoothService.cancelDiscovery(); 301 mBluetoothService.setIsDiscovering(false); 302 intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); 303 } 304 mContext.sendBroadcast(intent, BLUETOOTH_PERM); 305 mBluetoothService.setProperty(name, propValues[1]); 306 } else if (name.equals("Devices")) { 307 String value = null; 308 int len = Integer.valueOf(propValues[1]); 309 if (len > 0) { 310 StringBuilder str = new StringBuilder(); 311 for (int i = 2; i < propValues.length; i++) { 312 str.append(propValues[i]); 313 str.append(","); 314 } 315 value = str.toString(); 316 } 317 mBluetoothService.setProperty(name, value); 318 } else if (name.equals("Powered")) { 319 // bluetoothd has restarted, re-read all our properties. 320 // Note: bluez only sends this property change when it restarts. 321 if (propValues[1].equals("true")) 322 onRestartRequired(); 323 } 324 } 325 326 private void onDevicePropertyChanged(String deviceObjectPath, String[] propValues) { 327 String name = propValues[0]; 328 String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath); 329 if (address == null) { 330 Log.e(TAG, "onDevicePropertyChanged: Address of the remote device in null"); 331 return; 332 } 333 if (DBG) { 334 log("Device property changed:" + address + "property:" + name); 335 } 336 BluetoothDevice device = mAdapter.getRemoteDevice(address); 337 if (name.equals("Name")) { 338 Intent intent = new Intent(BluetoothDevice.ACTION_NAME_CHANGED); 339 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 340 intent.putExtra(BluetoothDevice.EXTRA_NAME, propValues[1]); 341 mContext.sendBroadcast(intent, BLUETOOTH_PERM); 342 mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]); 343 } else if (name.equals("Class")) { 344 Intent intent = new Intent(BluetoothDevice.ACTION_CLASS_CHANGED); 345 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 346 intent.putExtra(BluetoothDevice.EXTRA_CLASS, 347 new BluetoothClass(Integer.valueOf(propValues[1]))); 348 mContext.sendBroadcast(intent, BLUETOOTH_PERM); 349 mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]); 350 } else if (name.equals("Connected")) { 351 Intent intent = null; 352 if (propValues[1].equals("true")) { 353 intent = new Intent(BluetoothDevice.ACTION_ACL_CONNECTED); 354 } else { 355 intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECTED); 356 } 357 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 358 mContext.sendBroadcast(intent, BLUETOOTH_PERM); 359 mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]); 360 } else if (name.equals("UUIDs")) { 361 String uuid = null; 362 int len = Integer.valueOf(propValues[1]); 363 if (len > 0) { 364 StringBuilder str = new StringBuilder(); 365 for (int i = 2; i < propValues.length; i++) { 366 str.append(propValues[i]); 367 str.append(","); 368 } 369 uuid = str.toString(); 370 } 371 mBluetoothService.setRemoteDeviceProperty(address, name, uuid); 372 373 // UUIDs have changed, query remote service channel and update cache. 374 mBluetoothService.updateDeviceServiceChannelCache(address); 375 376 mBluetoothService.sendUuidIntent(address); 377 } else if (name.equals("Paired")) { 378 if (propValues[1].equals("true")) { 379 mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDED); 380 } else { 381 mBluetoothService.getBondState().setBondState(address, 382 BluetoothDevice.BOND_NONE); 383 mBluetoothService.setRemoteDeviceProperty(address, "Trusted", "false"); 384 } 385 } else if (name.equals("Trusted")) { 386 if (DBG) 387 log("set trust state succeded, value is " + propValues[1]); 388 mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]); 389 } 390 } 391 392 private String checkPairingRequestAndGetAddress(String objectPath, int nativeData) { 393 String address = mBluetoothService.getAddressFromObjectPath(objectPath); 394 if (address == null) { 395 Log.e(TAG, "Unable to get device address in checkPairingRequestAndGetAddress, " + 396 "returning null"); 397 return null; 398 } 399 address = address.toUpperCase(); 400 mPasskeyAgentRequestData.put(address, new Integer(nativeData)); 401 402 if (mBluetoothService.getBluetoothState() == BluetoothAdapter.STATE_TURNING_OFF) { 403 // shutdown path 404 mBluetoothService.cancelPairingUserInput(address); 405 return null; 406 } 407 return address; 408 } 409 410 private void onRequestPairingConsent(String objectPath, int nativeData) { 411 String address = checkPairingRequestAndGetAddress(objectPath, nativeData); 412 if (address == null) return; 413 414 /* The link key will not be stored if the incoming request has MITM 415 * protection switched on. Unfortunately, some devices have MITM 416 * switched on even though their capabilities are NoInputNoOutput, 417 * so we may get this request many times. Also if we respond immediately, 418 * the other end is unable to handle it. Delay sending the message. 419 */ 420 if (mBluetoothService.getBondState().getBondState(address) == BluetoothDevice.BOND_BONDED) { 421 Message message = mHandler.obtainMessage(EVENT_PAIRING_CONSENT_DELAYED_ACCEPT); 422 message.obj = address; 423 mHandler.sendMessageDelayed(message, 1500); 424 return; 425 } 426 427 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST); 428 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address)); 429 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, 430 BluetoothDevice.PAIRING_VARIANT_CONSENT); 431 mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM); 432 return; 433 } 434 435 private void onRequestPasskeyConfirmation(String objectPath, int passkey, int nativeData) { 436 String address = checkPairingRequestAndGetAddress(objectPath, nativeData); 437 if (address == null) return; 438 439 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST); 440 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address)); 441 intent.putExtra(BluetoothDevice.EXTRA_PASSKEY, passkey); 442 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, 443 BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION); 444 mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM); 445 return; 446 } 447 448 private void onRequestPasskey(String objectPath, int nativeData) { 449 String address = checkPairingRequestAndGetAddress(objectPath, nativeData); 450 if (address == null) return; 451 452 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST); 453 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address)); 454 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, 455 BluetoothDevice.PAIRING_VARIANT_PASSKEY); 456 mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM); 457 return; 458 } 459 460 private void onRequestPinCode(String objectPath, int nativeData) { 461 String address = checkPairingRequestAndGetAddress(objectPath, nativeData); 462 if (address == null) return; 463 464 String pendingOutgoingAddress = 465 mBluetoothService.getBondState().getPendingOutgoingBonding(); 466 if (address.equals(pendingOutgoingAddress)) { 467 // we initiated the bonding 468 BluetoothClass btClass = new BluetoothClass(mBluetoothService.getRemoteClass(address)); 469 470 // try 0000 once if the device looks dumb 471 switch (btClass.getDeviceClass()) { 472 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET: 473 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE: 474 case BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES: 475 case BluetoothClass.Device.AUDIO_VIDEO_PORTABLE_AUDIO: 476 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO: 477 case BluetoothClass.Device.AUDIO_VIDEO_HIFI_AUDIO: 478 if (!mBluetoothService.getBondState().hasAutoPairingFailed(address) && 479 !mBluetoothService.getBondState().isAutoPairingBlacklisted(address)) { 480 mBluetoothService.getBondState().attempt(address); 481 mBluetoothService.setPin(address, BluetoothDevice.convertPinToBytes("0000")); 482 return; 483 } 484 } 485 } 486 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST); 487 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address)); 488 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.PAIRING_VARIANT_PIN); 489 mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM); 490 return; 491 } 492 493 private void onDisplayPasskey(String objectPath, int passkey, int nativeData) { 494 String address = checkPairingRequestAndGetAddress(objectPath, nativeData); 495 if (address == null) return; 496 497 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST); 498 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address)); 499 intent.putExtra(BluetoothDevice.EXTRA_PASSKEY, passkey); 500 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, 501 BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY); 502 mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM); 503 } 504 505 private boolean onAgentAuthorize(String objectPath, String deviceUuid) { 506 String address = mBluetoothService.getAddressFromObjectPath(objectPath); 507 if (address == null) { 508 Log.e(TAG, "Unable to get device address in onAuthAgentAuthorize"); 509 return false; 510 } 511 512 boolean authorized = false; 513 ParcelUuid uuid = ParcelUuid.fromString(deviceUuid); 514 // Bluez sends the UUID of the local service being accessed, _not_ the 515 // remote service 516 if (mBluetoothService.isEnabled() && 517 (BluetoothUuid.isAudioSource(uuid) || BluetoothUuid.isAvrcpTarget(uuid) 518 || BluetoothUuid.isAdvAudioDist(uuid))) { 519 BluetoothA2dp a2dp = new BluetoothA2dp(mContext); 520 BluetoothDevice device = mAdapter.getRemoteDevice(address); 521 authorized = a2dp.getSinkPriority(device) > BluetoothA2dp.PRIORITY_OFF; 522 if (authorized) { 523 Log.i(TAG, "Allowing incoming A2DP / AVRCP connection from " + address); 524 } else { 525 Log.i(TAG, "Rejecting incoming A2DP / AVRCP connection from " + address); 526 } 527 } else { 528 Log.i(TAG, "Rejecting incoming " + deviceUuid + " connection from " + address); 529 } 530 log("onAgentAuthorize(" + objectPath + ", " + deviceUuid + ") = " + authorized); 531 return authorized; 532 } 533 534 private void onAgentCancel() { 535 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_CANCEL); 536 mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM); 537 return; 538 } 539 540 private void onDiscoverServicesResult(String deviceObjectPath, boolean result) { 541 String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath); 542 // We don't parse the xml here, instead just query Bluez for the properties. 543 if (result) { 544 mBluetoothService.updateRemoteDevicePropertiesCache(address); 545 } 546 mBluetoothService.sendUuidIntent(address); 547 } 548 549 private void onCreateDeviceResult(String address, boolean result) { 550 if (DBG) { 551 log("Result of onCreateDeviceResult:" + result); 552 } 553 if (!result) { 554 mBluetoothService.sendUuidIntent(address); 555 } 556 } 557 558 private void onRestartRequired() { 559 if (mBluetoothService.isEnabled()) { 560 Log.e(TAG, "*** A serious error occured (did bluetoothd crash?) - " + 561 "restarting Bluetooth ***"); 562 mHandler.sendEmptyMessage(EVENT_RESTART_BLUETOOTH); 563 } 564 } 565 566 private static void log(String msg) { 567 Log.d(TAG, msg); 568 } 569 570 private native void initializeNativeDataNative(); 571 private native void startEventLoopNative(); 572 private native void stopEventLoopNative(); 573 private native boolean isEventLoopRunningNative(); 574 private native void cleanupNativeDataNative(); 575} 576