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