1 /* 2 * Copyright (C) 2012 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.BluetoothProfile; 23 import android.bluetooth.BluetoothProtoEnums; 24 import android.bluetooth.OobData; 25 import android.content.Intent; 26 import android.os.Message; 27 import android.os.UserHandle; 28 import android.util.Log; 29 30 import com.android.bluetooth.BluetoothStatsLog; 31 import com.android.bluetooth.Utils; 32 import com.android.bluetooth.a2dp.A2dpService; 33 import com.android.bluetooth.a2dpsink.A2dpSinkService; 34 import com.android.bluetooth.btservice.RemoteDevices.DeviceProperties; 35 import com.android.bluetooth.hfp.HeadsetService; 36 import com.android.bluetooth.hfpclient.HeadsetClientService; 37 import com.android.bluetooth.hid.HidHostService; 38 import com.android.bluetooth.pbapclient.PbapClientService; 39 import com.android.bluetooth.statemachine.State; 40 import com.android.bluetooth.statemachine.StateMachine; 41 import com.android.internal.annotations.VisibleForTesting; 42 43 import java.util.ArrayList; 44 import java.util.HashSet; 45 import java.util.Objects; 46 import java.util.Set; 47 48 /** 49 * This state machine handles Bluetooth Adapter State. 50 * States: 51 * {@link StableState} : No device is in bonding / unbonding state. 52 * {@link PendingCommandState} : Some device is in bonding / unbonding state. 53 * TODO(BT) This class can be removed and this logic moved to the stack. 54 */ 55 56 final class BondStateMachine extends StateMachine { 57 private static final boolean DBG = false; 58 private static final String TAG = "BluetoothBondStateMachine"; 59 60 static final int CREATE_BOND = 1; 61 static final int CANCEL_BOND = 2; 62 static final int REMOVE_BOND = 3; 63 static final int BONDING_STATE_CHANGE = 4; 64 static final int SSP_REQUEST = 5; 65 static final int PIN_REQUEST = 6; 66 static final int UUID_UPDATE = 10; 67 static final int BOND_STATE_NONE = 0; 68 static final int BOND_STATE_BONDING = 1; 69 static final int BOND_STATE_BONDED = 2; 70 71 private AdapterService mAdapterService; 72 private AdapterProperties mAdapterProperties; 73 private RemoteDevices mRemoteDevices; 74 private BluetoothAdapter mAdapter; 75 76 private PendingCommandState mPendingCommandState = new PendingCommandState(); 77 private StableState mStableState = new StableState(); 78 79 public static final String OOBDATA = "oobdata"; 80 81 @VisibleForTesting Set<BluetoothDevice> mPendingBondedDevices = new HashSet<>(); 82 BondStateMachine(AdapterService service, AdapterProperties prop, RemoteDevices remoteDevices)83 private BondStateMachine(AdapterService service, AdapterProperties prop, 84 RemoteDevices remoteDevices) { 85 super("BondStateMachine:"); 86 addState(mStableState); 87 addState(mPendingCommandState); 88 mRemoteDevices = remoteDevices; 89 mAdapterService = service; 90 mAdapterProperties = prop; 91 mAdapter = BluetoothAdapter.getDefaultAdapter(); 92 setInitialState(mStableState); 93 } 94 make(AdapterService service, AdapterProperties prop, RemoteDevices remoteDevices)95 public static BondStateMachine make(AdapterService service, AdapterProperties prop, 96 RemoteDevices remoteDevices) { 97 Log.d(TAG, "make"); 98 BondStateMachine bsm = new BondStateMachine(service, prop, remoteDevices); 99 bsm.start(); 100 return bsm; 101 } 102 doQuit()103 public synchronized void doQuit() { 104 quitNow(); 105 } 106 cleanup()107 private void cleanup() { 108 mAdapterService = null; 109 mRemoteDevices = null; 110 mAdapterProperties = null; 111 } 112 113 @Override onQuitting()114 protected void onQuitting() { 115 cleanup(); 116 } 117 118 private class StableState extends State { 119 @Override enter()120 public void enter() { 121 infoLog("StableState(): Entering Off State"); 122 } 123 124 @Override processMessage(Message msg)125 public synchronized boolean processMessage(Message msg) { 126 127 BluetoothDevice dev = (BluetoothDevice) msg.obj; 128 129 switch (msg.what) { 130 131 case CREATE_BOND: 132 OobData oobData = null; 133 if (msg.getData() != null) { 134 oobData = msg.getData().getParcelable(OOBDATA); 135 } 136 137 createBond(dev, msg.arg1, oobData, true); 138 break; 139 case REMOVE_BOND: 140 removeBond(dev, true); 141 break; 142 case BONDING_STATE_CHANGE: 143 int newState = msg.arg1; 144 /* if incoming pairing, transition to pending state */ 145 if (newState == BluetoothDevice.BOND_BONDING) { 146 sendIntent(dev, newState, 0); 147 transitionTo(mPendingCommandState); 148 } else if (newState == BluetoothDevice.BOND_NONE) { 149 /* if the link key was deleted by the stack */ 150 sendIntent(dev, newState, 0); 151 } else { 152 Log.e(TAG, "In stable state, received invalid newState: " 153 + state2str(newState)); 154 } 155 break; 156 case UUID_UPDATE: 157 if (mPendingBondedDevices.contains(dev)) { 158 sendIntent(dev, BluetoothDevice.BOND_BONDED, 0); 159 } 160 break; 161 case CANCEL_BOND: 162 default: 163 Log.e(TAG, "Received unhandled state: " + msg.what); 164 return false; 165 } 166 return true; 167 } 168 } 169 170 171 private class PendingCommandState extends State { 172 private final ArrayList<BluetoothDevice> mDevices = new ArrayList<BluetoothDevice>(); 173 174 @Override enter()175 public void enter() { 176 infoLog("Entering PendingCommandState State"); 177 BluetoothDevice dev = (BluetoothDevice) getCurrentMessage().obj; 178 } 179 180 @Override processMessage(Message msg)181 public synchronized boolean processMessage(Message msg) { 182 BluetoothDevice dev = (BluetoothDevice) msg.obj; 183 DeviceProperties devProp = mRemoteDevices.getDeviceProperties(dev); 184 boolean result = false; 185 if (mDevices.contains(dev) && msg.what != CANCEL_BOND 186 && msg.what != BONDING_STATE_CHANGE && msg.what != SSP_REQUEST 187 && msg.what != PIN_REQUEST) { 188 deferMessage(msg); 189 return true; 190 } 191 192 switch (msg.what) { 193 case CREATE_BOND: 194 OobData oobData = null; 195 if (msg.getData() != null) { 196 oobData = msg.getData().getParcelable(OOBDATA); 197 } 198 199 result = createBond(dev, msg.arg1, oobData, false); 200 break; 201 case REMOVE_BOND: 202 result = removeBond(dev, false); 203 break; 204 case CANCEL_BOND: 205 result = cancelBond(dev); 206 break; 207 case BONDING_STATE_CHANGE: 208 int newState = msg.arg1; 209 int reason = getUnbondReasonFromHALCode(msg.arg2); 210 // Bond is explicitly removed if we are in pending command state 211 if (newState == BluetoothDevice.BOND_NONE 212 && reason == BluetoothDevice.BOND_SUCCESS) { 213 reason = BluetoothDevice.UNBOND_REASON_REMOVED; 214 } 215 sendIntent(dev, newState, reason); 216 if (newState != BluetoothDevice.BOND_BONDING) { 217 // This is either none/bonded, remove and transition, and also set 218 // result=false to avoid adding the device to mDevices. 219 mDevices.remove(dev); 220 result = false; 221 if (mDevices.isEmpty()) { 222 transitionTo(mStableState); 223 } 224 if (newState == BluetoothDevice.BOND_NONE) { 225 mAdapterService.setPhonebookAccessPermission(dev, 226 BluetoothDevice.ACCESS_UNKNOWN); 227 mAdapterService.setMessageAccessPermission(dev, 228 BluetoothDevice.ACCESS_UNKNOWN); 229 mAdapterService.setSimAccessPermission(dev, 230 BluetoothDevice.ACCESS_UNKNOWN); 231 // Set the profile Priorities to undefined 232 clearProfilePriority(dev); 233 } 234 } else if (!mDevices.contains(dev)) { 235 result = true; 236 } 237 break; 238 case SSP_REQUEST: 239 int passkey = msg.arg1; 240 int variant = msg.arg2; 241 sendDisplayPinIntent(devProp.getAddress(), passkey, variant); 242 break; 243 case PIN_REQUEST: 244 BluetoothClass btClass = dev.getBluetoothClass(); 245 int btDeviceClass = btClass.getDeviceClass(); 246 if (btDeviceClass == BluetoothClass.Device.PERIPHERAL_KEYBOARD || btDeviceClass 247 == BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING) { 248 // Its a keyboard. Follow the HID spec recommendation of creating the 249 // passkey and displaying it to the user. If the keyboard doesn't follow 250 // the spec recommendation, check if the keyboard has a fixed PIN zero 251 // and pair. 252 //TODO: Maintain list of devices that have fixed pin 253 // Generate a variable 6-digit PIN in range of 100000-999999 254 // This is not truly random but good enough. 255 int pin = 100000 + (int) Math.floor((Math.random() * (999999 - 100000))); 256 sendDisplayPinIntent(devProp.getAddress(), pin, 257 BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN); 258 break; 259 } 260 261 if (msg.arg2 == 1) { // Minimum 16 digit pin required here 262 sendDisplayPinIntent(devProp.getAddress(), 0, 263 BluetoothDevice.PAIRING_VARIANT_PIN_16_DIGITS); 264 } else { 265 // In PIN_REQUEST, there is no passkey to display.So do not send the 266 // EXTRA_PAIRING_KEY type in the intent( 0 in SendDisplayPinIntent() ) 267 sendDisplayPinIntent(devProp.getAddress(), 0, 268 BluetoothDevice.PAIRING_VARIANT_PIN); 269 } 270 271 break; 272 default: 273 Log.e(TAG, "Received unhandled event:" + msg.what); 274 return false; 275 } 276 if (result) { 277 mDevices.add(dev); 278 } 279 280 return true; 281 } 282 } 283 cancelBond(BluetoothDevice dev)284 private boolean cancelBond(BluetoothDevice dev) { 285 if (dev.getBondState() == BluetoothDevice.BOND_BONDING) { 286 byte[] addr = Utils.getBytesFromAddress(dev.getAddress()); 287 if (!mAdapterService.cancelBondNative(addr)) { 288 Log.e(TAG, "Unexpected error while cancelling bond:"); 289 } else { 290 return true; 291 } 292 } 293 return false; 294 } 295 removeBond(BluetoothDevice dev, boolean transition)296 private boolean removeBond(BluetoothDevice dev, boolean transition) { 297 DeviceProperties devProp = mRemoteDevices.getDeviceProperties(dev); 298 if (devProp != null && devProp.getBondState() == BluetoothDevice.BOND_BONDED) { 299 byte[] addr = Utils.getBytesFromAddress(dev.getAddress()); 300 if (!mAdapterService.removeBondNative(addr)) { 301 Log.e(TAG, "Unexpected error while removing bond:"); 302 } else { 303 if (transition) { 304 transitionTo(mPendingCommandState); 305 } 306 return true; 307 } 308 309 } 310 return false; 311 } 312 createBond(BluetoothDevice dev, int transport, OobData oobData, boolean transition)313 private boolean createBond(BluetoothDevice dev, int transport, OobData oobData, 314 boolean transition) { 315 if (dev.getBondState() == BluetoothDevice.BOND_NONE) { 316 infoLog("Bond address is:" + dev); 317 byte[] addr = Utils.getBytesFromAddress(dev.getAddress()); 318 boolean result; 319 if (oobData != null) { 320 result = mAdapterService.createBondOutOfBandNative(addr, transport, oobData); 321 } else { 322 result = mAdapterService.createBondNative(addr, transport); 323 } 324 BluetoothStatsLog.write(BluetoothStatsLog.BLUETOOTH_BOND_STATE_CHANGED, 325 mAdapterService.obfuscateAddress(dev), transport, dev.getType(), 326 BluetoothDevice.BOND_BONDING, 327 oobData == null ? BluetoothProtoEnums.BOND_SUB_STATE_UNKNOWN 328 : BluetoothProtoEnums.BOND_SUB_STATE_LOCAL_OOB_DATA_PROVIDED, 329 BluetoothProtoEnums.UNBOND_REASON_UNKNOWN); 330 if (!result) { 331 BluetoothStatsLog.write(BluetoothStatsLog.BLUETOOTH_BOND_STATE_CHANGED, 332 mAdapterService.obfuscateAddress(dev), transport, dev.getType(), 333 BluetoothDevice.BOND_NONE, BluetoothProtoEnums.BOND_SUB_STATE_UNKNOWN, 334 BluetoothDevice.UNBOND_REASON_REPEATED_ATTEMPTS); 335 // Using UNBOND_REASON_REMOVED for legacy reason 336 sendIntent(dev, BluetoothDevice.BOND_NONE, BluetoothDevice.UNBOND_REASON_REMOVED); 337 return false; 338 } else if (transition) { 339 transitionTo(mPendingCommandState); 340 } 341 return true; 342 } 343 return false; 344 } 345 sendDisplayPinIntent(byte[] address, int pin, int variant)346 private void sendDisplayPinIntent(byte[] address, int pin, int variant) { 347 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST); 348 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevices.getDevice(address)); 349 if (pin != 0) { 350 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, pin); 351 } 352 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, variant); 353 intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND); 354 // Workaround for Android Auto until pre-accepting pairing requests is added. 355 intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 356 mAdapterService.sendOrderedBroadcast(intent, AdapterService.BLUETOOTH_ADMIN_PERM); 357 } 358 359 @VisibleForTesting sendIntent(BluetoothDevice device, int newState, int reason)360 void sendIntent(BluetoothDevice device, int newState, int reason) { 361 DeviceProperties devProp = mRemoteDevices.getDeviceProperties(device); 362 int oldState = BluetoothDevice.BOND_NONE; 363 if (newState != BluetoothDevice.BOND_NONE 364 && newState != BluetoothDevice.BOND_BONDING 365 && newState != BluetoothDevice.BOND_BONDED) { 366 infoLog("Invalid bond state " + newState); 367 return; 368 } 369 if (devProp != null) { 370 oldState = devProp.getBondState(); 371 } 372 if (mPendingBondedDevices.contains(device)) { 373 mPendingBondedDevices.remove(device); 374 if (oldState == BluetoothDevice.BOND_BONDED) { 375 if (newState == BluetoothDevice.BOND_BONDING) { 376 mAdapterProperties.onBondStateChanged(device, newState); 377 } 378 oldState = BluetoothDevice.BOND_BONDING; 379 } else { 380 // Should not enter here. 381 throw new IllegalArgumentException("Invalid old state " + oldState); 382 } 383 } 384 if (oldState == newState) { 385 return; 386 } 387 BluetoothStatsLog.write(BluetoothStatsLog.BLUETOOTH_BOND_STATE_CHANGED, 388 mAdapterService.obfuscateAddress(device), 0, device.getType(), 389 newState, BluetoothProtoEnums.BOND_SUB_STATE_UNKNOWN, reason, 390 mAdapterService.getMetricId(device)); 391 BluetoothClass deviceClass = device.getBluetoothClass(); 392 int classOfDevice = deviceClass == null ? 0 : deviceClass.getClassOfDevice(); 393 BluetoothStatsLog.write(BluetoothStatsLog.BLUETOOTH_CLASS_OF_DEVICE_REPORTED, 394 mAdapterService.obfuscateAddress(device), classOfDevice, 395 mAdapterService.getMetricId(device)); 396 mAdapterProperties.onBondStateChanged(device, newState); 397 398 if (devProp != null && ((devProp.getDeviceType() == BluetoothDevice.DEVICE_TYPE_CLASSIC 399 || devProp.getDeviceType() == BluetoothDevice.DEVICE_TYPE_DUAL) 400 && newState == BluetoothDevice.BOND_BONDED && devProp.getUuids() == null)) { 401 infoLog(device + " is bonded, wait for SDP complete to broadcast bonded intent"); 402 if (!mPendingBondedDevices.contains(device)) { 403 mPendingBondedDevices.add(device); 404 } 405 if (oldState == BluetoothDevice.BOND_NONE) { 406 // Broadcast NONE->BONDING for NONE->BONDED case. 407 newState = BluetoothDevice.BOND_BONDING; 408 } else { 409 return; 410 } 411 } 412 413 Intent intent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED); 414 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 415 intent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, newState); 416 intent.putExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, oldState); 417 if (newState == BluetoothDevice.BOND_NONE) { 418 intent.putExtra(BluetoothDevice.EXTRA_REASON, reason); 419 } 420 mAdapterService.sendBroadcastAsUser(intent, UserHandle.ALL, AdapterService.BLUETOOTH_PERM); 421 infoLog("Bond State Change Intent:" + device + " " + state2str(oldState) + " => " 422 + state2str(newState)); 423 } 424 bondStateChangeCallback(int status, byte[] address, int newState)425 void bondStateChangeCallback(int status, byte[] address, int newState) { 426 BluetoothDevice device = mRemoteDevices.getDevice(address); 427 428 if (device == null) { 429 infoLog("No record of the device:" + device); 430 // This device will be added as part of the BONDING_STATE_CHANGE intent processing 431 // in sendIntent above 432 device = mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address)); 433 } 434 435 infoLog("bondStateChangeCallback: Status: " + status + " Address: " + device + " newState: " 436 + newState); 437 438 Message msg = obtainMessage(BONDING_STATE_CHANGE); 439 msg.obj = device; 440 441 if (newState == BOND_STATE_BONDED) { 442 msg.arg1 = BluetoothDevice.BOND_BONDED; 443 } else if (newState == BOND_STATE_BONDING) { 444 msg.arg1 = BluetoothDevice.BOND_BONDING; 445 } else { 446 msg.arg1 = BluetoothDevice.BOND_NONE; 447 } 448 msg.arg2 = status; 449 450 sendMessage(msg); 451 } 452 sspRequestCallback(byte[] address, byte[] name, int cod, int pairingVariant, int passkey)453 void sspRequestCallback(byte[] address, byte[] name, int cod, int pairingVariant, int passkey) { 454 //TODO(BT): Get wakelock and update name and cod 455 BluetoothDevice bdDevice = mRemoteDevices.getDevice(address); 456 if (bdDevice == null) { 457 mRemoteDevices.addDeviceProperties(address); 458 } 459 infoLog("sspRequestCallback: " + address + " name: " + name + " cod: " + cod 460 + " pairingVariant " + pairingVariant + " passkey: " + passkey); 461 int variant; 462 boolean displayPasskey = false; 463 switch (pairingVariant) { 464 465 case AbstractionLayer.BT_SSP_VARIANT_PASSKEY_CONFIRMATION: 466 variant = BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION; 467 displayPasskey = true; 468 break; 469 470 case AbstractionLayer.BT_SSP_VARIANT_CONSENT: 471 variant = BluetoothDevice.PAIRING_VARIANT_CONSENT; 472 break; 473 474 case AbstractionLayer.BT_SSP_VARIANT_PASSKEY_ENTRY: 475 variant = BluetoothDevice.PAIRING_VARIANT_PASSKEY; 476 break; 477 478 case AbstractionLayer.BT_SSP_VARIANT_PASSKEY_NOTIFICATION: 479 variant = BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY; 480 displayPasskey = true; 481 break; 482 483 default: 484 errorLog("SSP Pairing variant not present"); 485 return; 486 } 487 BluetoothDevice device = mRemoteDevices.getDevice(address); 488 if (device == null) { 489 warnLog("Device is not known for:" + Utils.getAddressStringFromByte(address)); 490 mRemoteDevices.addDeviceProperties(address); 491 device = Objects.requireNonNull(mRemoteDevices.getDevice(address)); 492 } 493 494 BluetoothStatsLog.write(BluetoothStatsLog.BLUETOOTH_BOND_STATE_CHANGED, 495 mAdapterService.obfuscateAddress(device), 0, device.getType(), 496 BluetoothDevice.BOND_BONDING, 497 BluetoothProtoEnums.BOND_SUB_STATE_LOCAL_SSP_REQUESTED, 0); 498 499 Message msg = obtainMessage(SSP_REQUEST); 500 msg.obj = device; 501 if (displayPasskey) { 502 msg.arg1 = passkey; 503 } 504 msg.arg2 = variant; 505 sendMessage(msg); 506 } 507 pinRequestCallback(byte[] address, byte[] name, int cod, boolean min16Digits)508 void pinRequestCallback(byte[] address, byte[] name, int cod, boolean min16Digits) { 509 //TODO(BT): Get wakelock and update name and cod 510 511 BluetoothDevice bdDevice = mRemoteDevices.getDevice(address); 512 if (bdDevice == null) { 513 mRemoteDevices.addDeviceProperties(address); 514 bdDevice = Objects.requireNonNull(mRemoteDevices.getDevice(address)); 515 } 516 517 BluetoothStatsLog.write(BluetoothStatsLog.BLUETOOTH_BOND_STATE_CHANGED, 518 mAdapterService.obfuscateAddress(bdDevice), 0, bdDevice.getType(), 519 BluetoothDevice.BOND_BONDING, 520 BluetoothProtoEnums.BOND_SUB_STATE_LOCAL_PIN_REQUESTED, 0); 521 522 infoLog("pinRequestCallback: " + bdDevice.getAddress() 523 + " name:" + bdDevice.getName() + " cod:" + new BluetoothClass(cod)); 524 525 Message msg = obtainMessage(PIN_REQUEST); 526 msg.obj = bdDevice; 527 msg.arg2 = min16Digits ? 1 : 0; // Use arg2 to pass the min16Digit boolean 528 529 sendMessage(msg); 530 } 531 clearProfilePriority(BluetoothDevice device)532 private void clearProfilePriority(BluetoothDevice device) { 533 HidHostService hidService = HidHostService.getHidHostService(); 534 A2dpService a2dpService = A2dpService.getA2dpService(); 535 HeadsetService headsetService = HeadsetService.getHeadsetService(); 536 HeadsetClientService headsetClientService = HeadsetClientService.getHeadsetClientService(); 537 A2dpSinkService a2dpSinkService = A2dpSinkService.getA2dpSinkService(); 538 PbapClientService pbapClientService = PbapClientService.getPbapClientService(); 539 540 if (hidService != null) { 541 hidService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_UNKNOWN); 542 } 543 if (a2dpService != null) { 544 a2dpService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_UNKNOWN); 545 } 546 if (headsetService != null) { 547 headsetService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_UNKNOWN); 548 } 549 if (headsetClientService != null) { 550 headsetClientService.setConnectionPolicy(device, 551 BluetoothProfile.CONNECTION_POLICY_UNKNOWN); 552 } 553 if (a2dpSinkService != null) { 554 a2dpSinkService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_UNKNOWN); 555 } 556 if (pbapClientService != null) { 557 pbapClientService.setConnectionPolicy(device, 558 BluetoothProfile.CONNECTION_POLICY_UNKNOWN); 559 } 560 } 561 state2str(int state)562 private String state2str(int state) { 563 if (state == BluetoothDevice.BOND_NONE) { 564 return "BOND_NONE"; 565 } else if (state == BluetoothDevice.BOND_BONDING) { 566 return "BOND_BONDING"; 567 } else if (state == BluetoothDevice.BOND_BONDED) { 568 return "BOND_BONDED"; 569 } else return "UNKNOWN(" + state + ")"; 570 } 571 infoLog(String msg)572 private void infoLog(String msg) { 573 Log.i(TAG, msg); 574 } 575 errorLog(String msg)576 private void errorLog(String msg) { 577 Log.e(TAG, msg); 578 } 579 warnLog(String msg)580 private void warnLog(String msg) { 581 Log.w(TAG, msg); 582 } 583 getUnbondReasonFromHALCode(int reason)584 private int getUnbondReasonFromHALCode(int reason) { 585 if (reason == AbstractionLayer.BT_STATUS_SUCCESS) { 586 return BluetoothDevice.BOND_SUCCESS; 587 } else if (reason == AbstractionLayer.BT_STATUS_RMT_DEV_DOWN) { 588 return BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN; 589 } else if (reason == AbstractionLayer.BT_STATUS_AUTH_FAILURE) { 590 return BluetoothDevice.UNBOND_REASON_AUTH_FAILED; 591 } else if (reason == AbstractionLayer.BT_STATUS_AUTH_REJECTED) { 592 return BluetoothDevice.UNBOND_REASON_AUTH_REJECTED; 593 } else if (reason == AbstractionLayer.BT_STATUS_AUTH_TIMEOUT) { 594 return BluetoothDevice.UNBOND_REASON_AUTH_TIMEOUT; 595 } 596 597 /* default */ 598 return BluetoothDevice.UNBOND_REASON_REMOVED; 599 } 600 } 601