/core/java/android/bluetooth/BluetoothDevice.java

http://github.com/android/platform_frameworks_base · Java · 2831 lines · 1297 code · 212 blank · 1322 comment · 124 complexity · 570bfa5bbe15ac9ce9465de88dbb882c MD5 · raw file

  1. /*
  2. * Copyright (C) 2009 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. package android.bluetooth;
  17. import android.annotation.IntDef;
  18. import android.annotation.NonNull;
  19. import android.annotation.Nullable;
  20. import android.annotation.RequiresPermission;
  21. import android.annotation.SdkConstant;
  22. import android.annotation.SdkConstant.SdkConstantType;
  23. import android.annotation.SuppressLint;
  24. import android.annotation.SystemApi;
  25. import android.app.PropertyInvalidatedCache;
  26. import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
  27. import android.bluetooth.annotations.RequiresBluetoothLocationPermission;
  28. import android.bluetooth.annotations.RequiresBluetoothScanPermission;
  29. import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
  30. import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
  31. import android.companion.AssociationRequest;
  32. import android.compat.annotation.UnsupportedAppUsage;
  33. import android.content.Attributable;
  34. import android.content.AttributionSource;
  35. import android.content.Context;
  36. import android.os.Build;
  37. import android.os.Handler;
  38. import android.os.Parcel;
  39. import android.os.ParcelUuid;
  40. import android.os.Parcelable;
  41. import android.os.Process;
  42. import android.os.RemoteException;
  43. import android.util.Log;
  44. import java.io.IOException;
  45. import java.io.UnsupportedEncodingException;
  46. import java.lang.annotation.Retention;
  47. import java.lang.annotation.RetentionPolicy;
  48. import java.util.UUID;
  49. /**
  50. * Represents a remote Bluetooth device. A {@link BluetoothDevice} lets you
  51. * create a connection with the respective device or query information about
  52. * it, such as the name, address, class, and bonding state.
  53. *
  54. * <p>This class is really just a thin wrapper for a Bluetooth hardware
  55. * address. Objects of this class are immutable. Operations on this class
  56. * are performed on the remote Bluetooth hardware address, using the
  57. * {@link BluetoothAdapter} that was used to create this {@link
  58. * BluetoothDevice}.
  59. *
  60. * <p>To get a {@link BluetoothDevice}, use
  61. * {@link BluetoothAdapter#getRemoteDevice(String)
  62. * BluetoothAdapter.getRemoteDevice(String)} to create one representing a device
  63. * of a known MAC address (which you can get through device discovery with
  64. * {@link BluetoothAdapter}) or get one from the set of bonded devices
  65. * returned by {@link BluetoothAdapter#getBondedDevices()
  66. * BluetoothAdapter.getBondedDevices()}. You can then open a
  67. * {@link BluetoothSocket} for communication with the remote device, using
  68. * {@link #createRfcommSocketToServiceRecord(UUID)} over Bluetooth BR/EDR or using
  69. * {@link #createL2capChannel(int)} over Bluetooth LE.
  70. *
  71. * <div class="special reference">
  72. * <h3>Developer Guides</h3>
  73. * <p>
  74. * For more information about using Bluetooth, read the <a href=
  75. * "{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer
  76. * guide.
  77. * </p>
  78. * </div>
  79. *
  80. * {@see BluetoothAdapter}
  81. * {@see BluetoothSocket}
  82. */
  83. public final class BluetoothDevice implements Parcelable, Attributable {
  84. private static final String TAG = "BluetoothDevice";
  85. private static final boolean DBG = false;
  86. /**
  87. * Connection state bitmask as returned by getConnectionState.
  88. */
  89. private static final int CONNECTION_STATE_DISCONNECTED = 0;
  90. private static final int CONNECTION_STATE_CONNECTED = 1;
  91. private static final int CONNECTION_STATE_ENCRYPTED_BREDR = 2;
  92. private static final int CONNECTION_STATE_ENCRYPTED_LE = 4;
  93. /**
  94. * Sentinel error value for this class. Guaranteed to not equal any other
  95. * integer constant in this class. Provided as a convenience for functions
  96. * that require a sentinel error value, for example:
  97. * <p><code>Intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
  98. * BluetoothDevice.ERROR)</code>
  99. */
  100. public static final int ERROR = Integer.MIN_VALUE;
  101. /**
  102. * Broadcast Action: Remote device discovered.
  103. * <p>Sent when a remote device is found during discovery.
  104. * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
  105. * #EXTRA_CLASS}. Can contain the extra fields {@link #EXTRA_NAME} and/or
  106. * {@link #EXTRA_RSSI} and/or {@link #EXTRA_IS_COORDINATED_SET_MEMBER} if they are available.
  107. */
  108. // TODO: Change API to not broadcast RSSI if not available (incoming connection)
  109. @RequiresLegacyBluetoothPermission
  110. @RequiresBluetoothScanPermission
  111. @RequiresBluetoothLocationPermission
  112. @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
  113. @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
  114. public static final String ACTION_FOUND =
  115. "android.bluetooth.device.action.FOUND";
  116. /**
  117. * Broadcast Action: Bluetooth class of a remote device has changed.
  118. * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
  119. * #EXTRA_CLASS}.
  120. * {@see BluetoothClass}
  121. */
  122. @RequiresLegacyBluetoothPermission
  123. @RequiresBluetoothConnectPermission
  124. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  125. @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
  126. public static final String ACTION_CLASS_CHANGED =
  127. "android.bluetooth.device.action.CLASS_CHANGED";
  128. /**
  129. * Broadcast Action: Indicates a low level (ACL) connection has been
  130. * established with a remote device.
  131. * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
  132. * <p>ACL connections are managed automatically by the Android Bluetooth
  133. * stack.
  134. */
  135. @RequiresLegacyBluetoothPermission
  136. @RequiresBluetoothConnectPermission
  137. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  138. @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
  139. public static final String ACTION_ACL_CONNECTED =
  140. "android.bluetooth.device.action.ACL_CONNECTED";
  141. /**
  142. * Broadcast Action: Indicates that a low level (ACL) disconnection has
  143. * been requested for a remote device, and it will soon be disconnected.
  144. * <p>This is useful for graceful disconnection. Applications should use
  145. * this intent as a hint to immediately terminate higher level connections
  146. * (RFCOMM, L2CAP, or profile connections) to the remote device.
  147. * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
  148. */
  149. @RequiresLegacyBluetoothPermission
  150. @RequiresBluetoothConnectPermission
  151. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  152. @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
  153. public static final String ACTION_ACL_DISCONNECT_REQUESTED =
  154. "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED";
  155. /**
  156. * Broadcast Action: Indicates a low level (ACL) disconnection from a
  157. * remote device.
  158. * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
  159. * <p>ACL connections are managed automatically by the Android Bluetooth
  160. * stack.
  161. */
  162. @RequiresLegacyBluetoothPermission
  163. @RequiresBluetoothConnectPermission
  164. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  165. @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
  166. public static final String ACTION_ACL_DISCONNECTED =
  167. "android.bluetooth.device.action.ACL_DISCONNECTED";
  168. /**
  169. * Broadcast Action: Indicates the friendly name of a remote device has
  170. * been retrieved for the first time, or changed since the last retrieval.
  171. * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
  172. * #EXTRA_NAME}.
  173. */
  174. @RequiresLegacyBluetoothPermission
  175. @RequiresBluetoothConnectPermission
  176. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  177. @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
  178. public static final String ACTION_NAME_CHANGED =
  179. "android.bluetooth.device.action.NAME_CHANGED";
  180. /**
  181. * Broadcast Action: Indicates the alias of a remote device has been
  182. * changed.
  183. * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
  184. */
  185. @SuppressLint("ActionValue")
  186. @RequiresLegacyBluetoothPermission
  187. @RequiresBluetoothConnectPermission
  188. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  189. @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
  190. public static final String ACTION_ALIAS_CHANGED =
  191. "android.bluetooth.device.action.ALIAS_CHANGED";
  192. /**
  193. * Broadcast Action: Indicates a change in the bond state of a remote
  194. * device. For example, if a device is bonded (paired).
  195. * <p>Always contains the extra fields {@link #EXTRA_DEVICE}, {@link
  196. * #EXTRA_BOND_STATE} and {@link #EXTRA_PREVIOUS_BOND_STATE}.
  197. */
  198. // Note: When EXTRA_BOND_STATE is BOND_NONE then this will also
  199. // contain a hidden extra field EXTRA_REASON with the result code.
  200. @RequiresLegacyBluetoothPermission
  201. @RequiresBluetoothConnectPermission
  202. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  203. @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
  204. public static final String ACTION_BOND_STATE_CHANGED =
  205. "android.bluetooth.device.action.BOND_STATE_CHANGED";
  206. /**
  207. * Broadcast Action: Indicates the battery level of a remote device has
  208. * been retrieved for the first time, or changed since the last retrieval
  209. * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
  210. * #EXTRA_BATTERY_LEVEL}.
  211. *
  212. * @hide
  213. */
  214. @RequiresLegacyBluetoothPermission
  215. @RequiresBluetoothConnectPermission
  216. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  217. @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
  218. public static final String ACTION_BATTERY_LEVEL_CHANGED =
  219. "android.bluetooth.device.action.BATTERY_LEVEL_CHANGED";
  220. /**
  221. * Used as an Integer extra field in {@link #ACTION_BATTERY_LEVEL_CHANGED}
  222. * intent. It contains the most recently retrieved battery level information
  223. * ranging from 0% to 100% for a remote device, {@link #BATTERY_LEVEL_UNKNOWN}
  224. * when the valid is unknown or there is an error
  225. *
  226. * @hide
  227. */
  228. public static final String EXTRA_BATTERY_LEVEL =
  229. "android.bluetooth.device.extra.BATTERY_LEVEL";
  230. /**
  231. * Used as the unknown value for {@link #EXTRA_BATTERY_LEVEL} and {@link #getBatteryLevel()}
  232. *
  233. * @hide
  234. */
  235. public static final int BATTERY_LEVEL_UNKNOWN = -1;
  236. /**
  237. * Used as an error value for {@link #getBatteryLevel()} to represent bluetooth is off
  238. *
  239. * @hide
  240. */
  241. public static final int BATTERY_LEVEL_BLUETOOTH_OFF = -100;
  242. /**
  243. * Used as a Parcelable {@link BluetoothDevice} extra field in every intent
  244. * broadcast by this class. It contains the {@link BluetoothDevice} that
  245. * the intent applies to.
  246. */
  247. public static final String EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE";
  248. /**
  249. * Used as a String extra field in {@link #ACTION_NAME_CHANGED} and {@link
  250. * #ACTION_FOUND} intents. It contains the friendly Bluetooth name.
  251. */
  252. public static final String EXTRA_NAME = "android.bluetooth.device.extra.NAME";
  253. /**
  254. * Used as an optional short extra field in {@link #ACTION_FOUND} intents.
  255. * Contains the RSSI value of the remote device as reported by the
  256. * Bluetooth hardware.
  257. */
  258. public static final String EXTRA_RSSI = "android.bluetooth.device.extra.RSSI";
  259. /**
  260. * Used as an bool extra field in {@link #ACTION_FOUND} intents.
  261. * It contains the information if device is discovered as member of a coordinated set or not.
  262. * Pairing with device that belongs to a set would trigger pairing with the rest of set members.
  263. * See Bluetooth CSIP specification for more details.
  264. */
  265. public static final String EXTRA_IS_COORDINATED_SET_MEMBER =
  266. "android.bluetooth.extra.IS_COORDINATED_SET_MEMBER";
  267. /**
  268. * Used as a Parcelable {@link BluetoothClass} extra field in {@link
  269. * #ACTION_FOUND} and {@link #ACTION_CLASS_CHANGED} intents.
  270. */
  271. public static final String EXTRA_CLASS = "android.bluetooth.device.extra.CLASS";
  272. /**
  273. * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents.
  274. * Contains the bond state of the remote device.
  275. * <p>Possible values are:
  276. * {@link #BOND_NONE},
  277. * {@link #BOND_BONDING},
  278. * {@link #BOND_BONDED}.
  279. */
  280. public static final String EXTRA_BOND_STATE = "android.bluetooth.device.extra.BOND_STATE";
  281. /**
  282. * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents.
  283. * Contains the previous bond state of the remote device.
  284. * <p>Possible values are:
  285. * {@link #BOND_NONE},
  286. * {@link #BOND_BONDING},
  287. * {@link #BOND_BONDED}.
  288. */
  289. public static final String EXTRA_PREVIOUS_BOND_STATE =
  290. "android.bluetooth.device.extra.PREVIOUS_BOND_STATE";
  291. /**
  292. * Indicates the remote device is not bonded (paired).
  293. * <p>There is no shared link key with the remote device, so communication
  294. * (if it is allowed at all) will be unauthenticated and unencrypted.
  295. */
  296. public static final int BOND_NONE = 10;
  297. /**
  298. * Indicates bonding (pairing) is in progress with the remote device.
  299. */
  300. public static final int BOND_BONDING = 11;
  301. /**
  302. * Indicates the remote device is bonded (paired).
  303. * <p>A shared link keys exists locally for the remote device, so
  304. * communication can be authenticated and encrypted.
  305. * <p><i>Being bonded (paired) with a remote device does not necessarily
  306. * mean the device is currently connected. It just means that the pending
  307. * procedure was completed at some earlier time, and the link key is still
  308. * stored locally, ready to use on the next connection.
  309. * </i>
  310. */
  311. public static final int BOND_BONDED = 12;
  312. /**
  313. * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST}
  314. * intents for unbond reason.
  315. *
  316. * @hide
  317. */
  318. @UnsupportedAppUsage
  319. public static final String EXTRA_REASON = "android.bluetooth.device.extra.REASON";
  320. /**
  321. * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST}
  322. * intents to indicate pairing method used. Possible values are:
  323. * {@link #PAIRING_VARIANT_PIN},
  324. * {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION},
  325. */
  326. public static final String EXTRA_PAIRING_VARIANT =
  327. "android.bluetooth.device.extra.PAIRING_VARIANT";
  328. /**
  329. * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST}
  330. * intents as the value of passkey.
  331. */
  332. public static final String EXTRA_PAIRING_KEY = "android.bluetooth.device.extra.PAIRING_KEY";
  333. /**
  334. * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST}
  335. * intents as the value of passkey.
  336. * @hide
  337. */
  338. public static final String EXTRA_PAIRING_INITIATOR =
  339. "android.bluetooth.device.extra.PAIRING_INITIATOR";
  340. /**
  341. * Bluetooth pairing initiator, Foreground App
  342. * @hide
  343. */
  344. public static final int EXTRA_PAIRING_INITIATOR_FOREGROUND = 1;
  345. /**
  346. * Bluetooth pairing initiator, Background
  347. * @hide
  348. */
  349. public static final int EXTRA_PAIRING_INITIATOR_BACKGROUND = 2;
  350. /**
  351. * Bluetooth device type, Unknown
  352. */
  353. public static final int DEVICE_TYPE_UNKNOWN = 0;
  354. /**
  355. * Bluetooth device type, Classic - BR/EDR devices
  356. */
  357. public static final int DEVICE_TYPE_CLASSIC = 1;
  358. /**
  359. * Bluetooth device type, Low Energy - LE-only
  360. */
  361. public static final int DEVICE_TYPE_LE = 2;
  362. /**
  363. * Bluetooth device type, Dual Mode - BR/EDR/LE
  364. */
  365. public static final int DEVICE_TYPE_DUAL = 3;
  366. /** @hide */
  367. @RequiresBluetoothConnectPermission
  368. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  369. @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
  370. @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
  371. public static final String ACTION_SDP_RECORD =
  372. "android.bluetooth.device.action.SDP_RECORD";
  373. /** @hide */
  374. @IntDef(prefix = "METADATA_", value = {
  375. METADATA_MANUFACTURER_NAME,
  376. METADATA_MODEL_NAME,
  377. METADATA_SOFTWARE_VERSION,
  378. METADATA_HARDWARE_VERSION,
  379. METADATA_COMPANION_APP,
  380. METADATA_MAIN_ICON,
  381. METADATA_IS_UNTETHERED_HEADSET,
  382. METADATA_UNTETHERED_LEFT_ICON,
  383. METADATA_UNTETHERED_RIGHT_ICON,
  384. METADATA_UNTETHERED_CASE_ICON,
  385. METADATA_UNTETHERED_LEFT_BATTERY,
  386. METADATA_UNTETHERED_RIGHT_BATTERY,
  387. METADATA_UNTETHERED_CASE_BATTERY,
  388. METADATA_UNTETHERED_LEFT_CHARGING,
  389. METADATA_UNTETHERED_RIGHT_CHARGING,
  390. METADATA_UNTETHERED_CASE_CHARGING,
  391. METADATA_ENHANCED_SETTINGS_UI_URI,
  392. METADATA_DEVICE_TYPE,
  393. METADATA_MAIN_BATTERY,
  394. METADATA_MAIN_CHARGING,
  395. METADATA_MAIN_LOW_BATTERY_THRESHOLD,
  396. METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD,
  397. METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD,
  398. METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD})
  399. @Retention(RetentionPolicy.SOURCE)
  400. public @interface MetadataKey{}
  401. /**
  402. * Maximum length of a metadata entry, this is to avoid exploding Bluetooth
  403. * disk usage
  404. * @hide
  405. */
  406. @SystemApi
  407. public static final int METADATA_MAX_LENGTH = 2048;
  408. /**
  409. * Manufacturer name of this Bluetooth device
  410. * Data type should be {@String} as {@link Byte} array.
  411. * @hide
  412. */
  413. @SystemApi
  414. public static final int METADATA_MANUFACTURER_NAME = 0;
  415. /**
  416. * Model name of this Bluetooth device
  417. * Data type should be {@String} as {@link Byte} array.
  418. * @hide
  419. */
  420. @SystemApi
  421. public static final int METADATA_MODEL_NAME = 1;
  422. /**
  423. * Software version of this Bluetooth device
  424. * Data type should be {@String} as {@link Byte} array.
  425. * @hide
  426. */
  427. @SystemApi
  428. public static final int METADATA_SOFTWARE_VERSION = 2;
  429. /**
  430. * Hardware version of this Bluetooth device
  431. * Data type should be {@String} as {@link Byte} array.
  432. * @hide
  433. */
  434. @SystemApi
  435. public static final int METADATA_HARDWARE_VERSION = 3;
  436. /**
  437. * Package name of the companion app, if any
  438. * Data type should be {@String} as {@link Byte} array.
  439. * @hide
  440. */
  441. @SystemApi
  442. public static final int METADATA_COMPANION_APP = 4;
  443. /**
  444. * URI to the main icon shown on the settings UI
  445. * Data type should be {@link Byte} array.
  446. * @hide
  447. */
  448. @SystemApi
  449. public static final int METADATA_MAIN_ICON = 5;
  450. /**
  451. * Whether this device is an untethered headset with left, right and case
  452. * Data type should be {@String} as {@link Byte} array.
  453. * @hide
  454. */
  455. @SystemApi
  456. public static final int METADATA_IS_UNTETHERED_HEADSET = 6;
  457. /**
  458. * URI to icon of the left headset
  459. * Data type should be {@link Byte} array.
  460. * @hide
  461. */
  462. @SystemApi
  463. public static final int METADATA_UNTETHERED_LEFT_ICON = 7;
  464. /**
  465. * URI to icon of the right headset
  466. * Data type should be {@link Byte} array.
  467. * @hide
  468. */
  469. @SystemApi
  470. public static final int METADATA_UNTETHERED_RIGHT_ICON = 8;
  471. /**
  472. * URI to icon of the headset charging case
  473. * Data type should be {@link Byte} array.
  474. * @hide
  475. */
  476. @SystemApi
  477. public static final int METADATA_UNTETHERED_CASE_ICON = 9;
  478. /**
  479. * Battery level of left headset
  480. * Data type should be {@String} 0-100 as {@link Byte} array, otherwise
  481. * as invalid.
  482. * @hide
  483. */
  484. @SystemApi
  485. public static final int METADATA_UNTETHERED_LEFT_BATTERY = 10;
  486. /**
  487. * Battery level of rigth headset
  488. * Data type should be {@String} 0-100 as {@link Byte} array, otherwise
  489. * as invalid.
  490. * @hide
  491. */
  492. @SystemApi
  493. public static final int METADATA_UNTETHERED_RIGHT_BATTERY = 11;
  494. /**
  495. * Battery level of the headset charging case
  496. * Data type should be {@String} 0-100 as {@link Byte} array, otherwise
  497. * as invalid.
  498. * @hide
  499. */
  500. @SystemApi
  501. public static final int METADATA_UNTETHERED_CASE_BATTERY = 12;
  502. /**
  503. * Whether the left headset is charging
  504. * Data type should be {@String} as {@link Byte} array.
  505. * @hide
  506. */
  507. @SystemApi
  508. public static final int METADATA_UNTETHERED_LEFT_CHARGING = 13;
  509. /**
  510. * Whether the right headset is charging
  511. * Data type should be {@String} as {@link Byte} array.
  512. * @hide
  513. */
  514. @SystemApi
  515. public static final int METADATA_UNTETHERED_RIGHT_CHARGING = 14;
  516. /**
  517. * Whether the headset charging case is charging
  518. * Data type should be {@String} as {@link Byte} array.
  519. * @hide
  520. */
  521. @SystemApi
  522. public static final int METADATA_UNTETHERED_CASE_CHARGING = 15;
  523. /**
  524. * URI to the enhanced settings UI slice
  525. * Data type should be {@String} as {@link Byte} array, null means
  526. * the UI does not exist.
  527. * @hide
  528. */
  529. @SystemApi
  530. public static final int METADATA_ENHANCED_SETTINGS_UI_URI = 16;
  531. /**
  532. * Type of the Bluetooth device, must be within the list of
  533. * BluetoothDevice.DEVICE_TYPE_*
  534. * Data type should be {@String} as {@link Byte} array.
  535. * @hide
  536. */
  537. @SystemApi
  538. public static final int METADATA_DEVICE_TYPE = 17;
  539. /**
  540. * Battery level of the Bluetooth device, use when the Bluetooth device
  541. * does not support HFP battery indicator.
  542. * Data type should be {@String} as {@link Byte} array.
  543. * @hide
  544. */
  545. @SystemApi
  546. public static final int METADATA_MAIN_BATTERY = 18;
  547. /**
  548. * Whether the device is charging.
  549. * Data type should be {@String} as {@link Byte} array.
  550. * @hide
  551. */
  552. @SystemApi
  553. public static final int METADATA_MAIN_CHARGING = 19;
  554. /**
  555. * The battery threshold of the Bluetooth device to show low battery icon.
  556. * Data type should be {@String} as {@link Byte} array.
  557. * @hide
  558. */
  559. @SystemApi
  560. public static final int METADATA_MAIN_LOW_BATTERY_THRESHOLD = 20;
  561. /**
  562. * The battery threshold of the left headset to show low battery icon.
  563. * Data type should be {@String} as {@link Byte} array.
  564. * @hide
  565. */
  566. @SystemApi
  567. public static final int METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD = 21;
  568. /**
  569. * The battery threshold of the right headset to show low battery icon.
  570. * Data type should be {@String} as {@link Byte} array.
  571. * @hide
  572. */
  573. @SystemApi
  574. public static final int METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD = 22;
  575. /**
  576. * The battery threshold of the case to show low battery icon.
  577. * Data type should be {@String} as {@link Byte} array.
  578. * @hide
  579. */
  580. @SystemApi
  581. public static final int METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD = 23;
  582. /**
  583. * Device type which is used in METADATA_DEVICE_TYPE
  584. * Indicates this Bluetooth device is a standard Bluetooth accessory or
  585. * not listed in METADATA_DEVICE_TYPE_*.
  586. * @hide
  587. */
  588. @SystemApi
  589. public static final String DEVICE_TYPE_DEFAULT = "Default";
  590. /**
  591. * Device type which is used in METADATA_DEVICE_TYPE
  592. * Indicates this Bluetooth device is a watch.
  593. * @hide
  594. */
  595. @SystemApi
  596. public static final String DEVICE_TYPE_WATCH = "Watch";
  597. /**
  598. * Device type which is used in METADATA_DEVICE_TYPE
  599. * Indicates this Bluetooth device is an untethered headset.
  600. * @hide
  601. */
  602. @SystemApi
  603. public static final String DEVICE_TYPE_UNTETHERED_HEADSET = "Untethered Headset";
  604. /**
  605. * Broadcast Action: This intent is used to broadcast the {@link UUID}
  606. * wrapped as a {@link android.os.ParcelUuid} of the remote device after it
  607. * has been fetched. This intent is sent only when the UUIDs of the remote
  608. * device are requested to be fetched using Service Discovery Protocol
  609. * <p> Always contains the extra field {@link #EXTRA_DEVICE}
  610. * <p> Always contains the extra field {@link #EXTRA_UUID}
  611. */
  612. @RequiresLegacyBluetoothAdminPermission
  613. @RequiresBluetoothConnectPermission
  614. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  615. @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
  616. public static final String ACTION_UUID =
  617. "android.bluetooth.device.action.UUID";
  618. /** @hide */
  619. @RequiresBluetoothConnectPermission
  620. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  621. @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
  622. public static final String ACTION_MAS_INSTANCE =
  623. "android.bluetooth.device.action.MAS_INSTANCE";
  624. /**
  625. * Broadcast Action: Indicates a failure to retrieve the name of a remote
  626. * device.
  627. * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
  628. *
  629. * @hide
  630. */
  631. //TODO: is this actually useful?
  632. @RequiresLegacyBluetoothPermission
  633. @RequiresBluetoothConnectPermission
  634. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  635. @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
  636. public static final String ACTION_NAME_FAILED =
  637. "android.bluetooth.device.action.NAME_FAILED";
  638. /**
  639. * Broadcast Action: This intent is used to broadcast PAIRING REQUEST
  640. */
  641. @RequiresLegacyBluetoothAdminPermission
  642. @RequiresBluetoothConnectPermission
  643. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  644. @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
  645. public static final String ACTION_PAIRING_REQUEST =
  646. "android.bluetooth.device.action.PAIRING_REQUEST";
  647. /** @hide */
  648. @RequiresBluetoothConnectPermission
  649. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  650. @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
  651. @UnsupportedAppUsage
  652. public static final String ACTION_PAIRING_CANCEL =
  653. "android.bluetooth.device.action.PAIRING_CANCEL";
  654. /** @hide */
  655. @RequiresBluetoothConnectPermission
  656. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  657. @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
  658. public static final String ACTION_CONNECTION_ACCESS_REQUEST =
  659. "android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST";
  660. /** @hide */
  661. @RequiresBluetoothConnectPermission
  662. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  663. @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
  664. public static final String ACTION_CONNECTION_ACCESS_REPLY =
  665. "android.bluetooth.device.action.CONNECTION_ACCESS_REPLY";
  666. /** @hide */
  667. @RequiresBluetoothConnectPermission
  668. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  669. @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
  670. public static final String ACTION_CONNECTION_ACCESS_CANCEL =
  671. "android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL";
  672. /**
  673. * Intent to broadcast silence mode changed.
  674. * Alway contains the extra field {@link #EXTRA_DEVICE}
  675. *
  676. * @hide
  677. */
  678. @RequiresBluetoothConnectPermission
  679. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  680. @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
  681. @SystemApi
  682. public static final String ACTION_SILENCE_MODE_CHANGED =
  683. "android.bluetooth.device.action.SILENCE_MODE_CHANGED";
  684. /**
  685. * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intent.
  686. *
  687. * @hide
  688. */
  689. public static final String EXTRA_ACCESS_REQUEST_TYPE =
  690. "android.bluetooth.device.extra.ACCESS_REQUEST_TYPE";
  691. /** @hide */
  692. public static final int REQUEST_TYPE_PROFILE_CONNECTION = 1;
  693. /** @hide */
  694. public static final int REQUEST_TYPE_PHONEBOOK_ACCESS = 2;
  695. /** @hide */
  696. public static final int REQUEST_TYPE_MESSAGE_ACCESS = 3;
  697. /** @hide */
  698. public static final int REQUEST_TYPE_SIM_ACCESS = 4;
  699. /**
  700. * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents,
  701. * Contains package name to return reply intent to.
  702. *
  703. * @hide
  704. */
  705. public static final String EXTRA_PACKAGE_NAME = "android.bluetooth.device.extra.PACKAGE_NAME";
  706. /**
  707. * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents,
  708. * Contains class name to return reply intent to.
  709. *
  710. * @hide
  711. */
  712. public static final String EXTRA_CLASS_NAME = "android.bluetooth.device.extra.CLASS_NAME";
  713. /**
  714. * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intent.
  715. *
  716. * @hide
  717. */
  718. public static final String EXTRA_CONNECTION_ACCESS_RESULT =
  719. "android.bluetooth.device.extra.CONNECTION_ACCESS_RESULT";
  720. /** @hide */
  721. public static final int CONNECTION_ACCESS_YES = 1;
  722. /** @hide */
  723. public static final int CONNECTION_ACCESS_NO = 2;
  724. /**
  725. * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intents,
  726. * Contains boolean to indicate if the allowed response is once-for-all so that
  727. * next request will be granted without asking user again.
  728. *
  729. * @hide
  730. */
  731. public static final String EXTRA_ALWAYS_ALLOWED =
  732. "android.bluetooth.device.extra.ALWAYS_ALLOWED";
  733. /**
  734. * A bond attempt succeeded
  735. *
  736. * @hide
  737. */
  738. public static final int BOND_SUCCESS = 0;
  739. /**
  740. * A bond attempt failed because pins did not match, or remote device did
  741. * not respond to pin request in time
  742. *
  743. * @hide
  744. */
  745. @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
  746. public static final int UNBOND_REASON_AUTH_FAILED = 1;
  747. /**
  748. * A bond attempt failed because the other side explicitly rejected
  749. * bonding
  750. *
  751. * @hide
  752. */
  753. @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
  754. public static final int UNBOND_REASON_AUTH_REJECTED = 2;
  755. /**
  756. * A bond attempt failed because we canceled the bonding process
  757. *
  758. * @hide
  759. */
  760. public static final int UNBOND_REASON_AUTH_CANCELED = 3;
  761. /**
  762. * A bond attempt failed because we could not contact the remote device
  763. *
  764. * @hide
  765. */
  766. @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
  767. public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4;
  768. /**
  769. * A bond attempt failed because a discovery is in progress
  770. *
  771. * @hide
  772. */
  773. @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
  774. public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5;
  775. /**
  776. * A bond attempt failed because of authentication timeout
  777. *
  778. * @hide
  779. */
  780. @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
  781. public static final int UNBOND_REASON_AUTH_TIMEOUT = 6;
  782. /**
  783. * A bond attempt failed because of repeated attempts
  784. *
  785. * @hide
  786. */
  787. @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
  788. public static final int UNBOND_REASON_REPEATED_ATTEMPTS = 7;
  789. /**
  790. * A bond attempt failed because we received an Authentication Cancel
  791. * by remote end
  792. *
  793. * @hide
  794. */
  795. @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
  796. public static final int UNBOND_REASON_REMOTE_AUTH_CANCELED = 8;
  797. /**
  798. * An existing bond was explicitly revoked
  799. *
  800. * @hide
  801. */
  802. public static final int UNBOND_REASON_REMOVED = 9;
  803. /**
  804. * The user will be prompted to enter a pin or
  805. * an app will enter a pin for user.
  806. */
  807. public static final int PAIRING_VARIANT_PIN = 0;
  808. /**
  809. * The user will be prompted to enter a passkey
  810. *
  811. * @hide
  812. */
  813. public static final int PAIRING_VARIANT_PASSKEY = 1;
  814. /**
  815. * The user will be prompted to confirm the passkey displayed on the screen or
  816. * an app will confirm the passkey for the user.
  817. */
  818. public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2;
  819. /**
  820. * The user will be prompted to accept or deny the incoming pairing request
  821. *
  822. * @hide
  823. */
  824. public static final int PAIRING_VARIANT_CONSENT = 3;
  825. /**
  826. * The user will be prompted to enter the passkey displayed on remote device
  827. * This is used for Bluetooth 2.1 pairing.
  828. *
  829. * @hide
  830. */
  831. public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4;
  832. /**
  833. * The user will be prompted to enter the PIN displayed on remote device.
  834. * This is used for Bluetooth 2.0 pairing.
  835. *
  836. * @hide
  837. */
  838. public static final int PAIRING_VARIANT_DISPLAY_PIN = 5;
  839. /**
  840. * The user will be prompted to accept or deny the OOB pairing request
  841. *
  842. * @hide
  843. */
  844. public static final int PAIRING_VARIANT_OOB_CONSENT = 6;
  845. /**
  846. * The user will be prompted to enter a 16 digit pin or
  847. * an app will enter a 16 digit pin for user.
  848. *
  849. * @hide
  850. */
  851. public static final int PAIRING_VARIANT_PIN_16_DIGITS = 7;
  852. /**
  853. * Used as an extra field in {@link #ACTION_UUID} intents,
  854. * Contains the {@link android.os.ParcelUuid}s of the remote device which
  855. * is a parcelable version of {@link UUID}.
  856. */
  857. public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
  858. /** @hide */
  859. public static final String EXTRA_SDP_RECORD =
  860. "android.bluetooth.device.extra.SDP_RECORD";
  861. /** @hide */
  862. @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
  863. public static final String EXTRA_SDP_SEARCH_STATUS =
  864. "android.bluetooth.device.extra.SDP_SEARCH_STATUS";
  865. /** @hide */
  866. @IntDef(prefix = "ACCESS_", value = {ACCESS_UNKNOWN,
  867. ACCESS_ALLOWED, ACCESS_REJECTED})
  868. @Retention(RetentionPolicy.SOURCE)
  869. public @interface AccessPermission{}
  870. /**
  871. * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
  872. * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
  873. *
  874. * @hide
  875. */
  876. @SystemApi
  877. public static final int ACCESS_UNKNOWN = 0;
  878. /**
  879. * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
  880. * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
  881. *
  882. * @hide
  883. */
  884. @SystemApi
  885. public static final int ACCESS_ALLOWED = 1;
  886. /**
  887. * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
  888. * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
  889. *
  890. * @hide
  891. */
  892. @SystemApi
  893. public static final int ACCESS_REJECTED = 2;
  894. /** @hide */
  895. @Retention(RetentionPolicy.SOURCE)
  896. @IntDef(
  897. prefix = { "TRANSPORT_" },
  898. value = {
  899. /** Allow host to automatically select a transport (dual-mode only) */
  900. TRANSPORT_AUTO,
  901. /** Use Classic or BR/EDR transport.*/
  902. TRANSPORT_BREDR,
  903. /** Use Low Energy transport.*/
  904. TRANSPORT_LE,
  905. }
  906. )
  907. public @interface Transport {}
  908. /**
  909. * No preference of physical transport for GATT connections to remote dual-mode devices
  910. */
  911. public static final int TRANSPORT_AUTO = 0;
  912. /**
  913. * Prefer BR/EDR transport for GATT connections to remote dual-mode devices
  914. */
  915. public static final int TRANSPORT_BREDR = 1;
  916. /**
  917. * Prefer LE transport for GATT connections to remote dual-mode devices
  918. */
  919. public static final int TRANSPORT_LE = 2;
  920. /**
  921. * Bluetooth LE 1M PHY. Used to refer to LE 1M Physical Channel for advertising, scanning or
  922. * connection.
  923. */
  924. public static final int PHY_LE_1M = 1;
  925. /**
  926. * Bluetooth LE 2M PHY. Used to refer to LE 2M Physical Channel for advertising, scanning or
  927. * connection.
  928. */
  929. public static final int PHY_LE_2M = 2;
  930. /**
  931. * Bluetooth LE Coded PHY. Used to refer to LE Coded Physical Channel for advertising, scanning
  932. * or connection.
  933. */
  934. public static final int PHY_LE_CODED = 3;
  935. /**
  936. * Bluetooth LE 1M PHY mask. Used to specify LE 1M Physical Channel as one of many available
  937. * options in a bitmask.
  938. */
  939. public static final int PHY_LE_1M_MASK = 1;
  940. /**
  941. * Bluetooth LE 2M PHY mask. Used to specify LE 2M Physical Channel as one of many available
  942. * options in a bitmask.
  943. */
  944. public static final int PHY_LE_2M_MASK = 2;
  945. /**
  946. * Bluetooth LE Coded PHY mask. Used to specify LE Coded Physical Channel as one of many
  947. * available options in a bitmask.
  948. */
  949. public static final int PHY_LE_CODED_MASK = 4;
  950. /**
  951. * No preferred coding when transmitting on the LE Coded PHY.
  952. */
  953. public static final int PHY_OPTION_NO_PREFERRED = 0;
  954. /**
  955. * Prefer the S=2 coding to be used when transmitting on the LE Coded PHY.
  956. */
  957. public static final int PHY_OPTION_S2 = 1;
  958. /**
  959. * Prefer the S=8 coding to be used when transmitting on the LE Coded PHY.
  960. */
  961. public static final int PHY_OPTION_S8 = 2;
  962. /** @hide */
  963. public static final String EXTRA_MAS_INSTANCE =
  964. "android.bluetooth.device.extra.MAS_INSTANCE";
  965. /** @hide */
  966. @Retention(RetentionPolicy.SOURCE)
  967. @IntDef(
  968. prefix = { "ADDRESS_TYPE_" },
  969. value = {
  970. /** Hardware MAC Address */
  971. ADDRESS_TYPE_PUBLIC,
  972. /** Address is either resolvable, non-resolvable or static.*/
  973. ADDRESS_TYPE_RANDOM,
  974. }
  975. )
  976. public @interface AddressType {}
  977. /** Hardware MAC Address of the device */
  978. public static final int ADDRESS_TYPE_PUBLIC = 0;
  979. /** Address is either resolvable, non-resolvable or static. */
  980. public static final int ADDRESS_TYPE_RANDOM = 1;
  981. private static final String NULL_MAC_ADDRESS = "00:00:00:00:00:00";
  982. /**
  983. * Lazy initialization. Guaranteed final after first object constructed, or
  984. * getService() called.
  985. * TODO: Unify implementation of sService amongst BluetoothFoo API's
  986. */
  987. private static volatile IBluetooth sService;
  988. private final String mAddress;
  989. @AddressType private final int mAddressType;
  990. private AttributionSource mAttributionSource;
  991. /*package*/
  992. @UnsupportedAppUsage
  993. static IBluetooth getService() {
  994. synchronized (BluetoothDevice.class) {
  995. if (sService == null) {
  996. BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
  997. sService = adapter.getBluetoothService(sStateChangeCallback);
  998. }
  999. }
  1000. return sService;
  1001. }
  1002. static IBluetoothManagerCallback sStateChangeCallback = new IBluetoothManagerCallback.Stub() {
  1003. public void onBluetoothServiceUp(IBluetooth bluetoothService)
  1004. throws RemoteException {
  1005. synchronized (BluetoothDevice.class) {
  1006. if (sService == null) {
  1007. sService = bluetoothService;
  1008. }
  1009. }
  1010. }
  1011. public void onBluetoothServiceDown()
  1012. throws RemoteException {
  1013. synchronized (BluetoothDevice.class) {
  1014. sService = null;
  1015. }
  1016. }
  1017. public void onBrEdrDown() {
  1018. if (DBG) Log.d(TAG, "onBrEdrDown: reached BLE ON state");
  1019. }
  1020. public void onOobData(@Transport int transport, OobData oobData) {
  1021. if (DBG) Log.d(TAG, "onOobData: got data");
  1022. }
  1023. };
  1024. /**
  1025. * Create a new BluetoothDevice
  1026. * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB",
  1027. * and is validated in this constructor.
  1028. *
  1029. * @param address valid Bluetooth MAC address
  1030. * @param attributionSource attribution for permission-protected calls
  1031. * @throws RuntimeException Bluetooth is not available on this platform
  1032. * @throws IllegalArgumentException address is invalid
  1033. * @hide
  1034. */
  1035. @UnsupportedAppUsage
  1036. /*package*/ BluetoothDevice(String address) {
  1037. getService(); // ensures sService is initialized
  1038. if (!BluetoothAdapter.checkBluetoothAddress(address)) {
  1039. throw new IllegalArgumentException(address + " is not a valid Bluetooth address");
  1040. }
  1041. mAddress = address;
  1042. mAddressType = ADDRESS_TYPE_PUBLIC;
  1043. mAttributionSource = BluetoothManager.resolveAttributionSource(null);
  1044. }
  1045. /** {@hide} */
  1046. public void setAttributionSource(@NonNull AttributionSource attributionSource) {
  1047. mAttributionSource = attributionSource;
  1048. }
  1049. /** {@hide} */
  1050. public void prepareToEnterProcess(@NonNull AttributionSource attributionSource) {
  1051. setAttributionSource(attributionSource);
  1052. }
  1053. @Override
  1054. public boolean equals(@Nullable Object o) {
  1055. if (o instanceof BluetoothDevice) {
  1056. return mAddress.equals(((BluetoothDevice) o).getAddress());
  1057. }
  1058. return false;
  1059. }
  1060. @Override
  1061. public int hashCode() {
  1062. return mAddress.hashCode();
  1063. }
  1064. /**
  1065. * Returns a string representation of this BluetoothDevice.
  1066. * <p>Currently this is the Bluetooth hardware address, for example
  1067. * "00:11:22:AA:BB:CC". However, you should always use {@link #getAddress}
  1068. * if you explicitly require the Bluetooth hardware address in case the
  1069. * {@link #toString} representation changes in the future.
  1070. *
  1071. * @return string representation of this BluetoothDevice
  1072. */
  1073. @Override
  1074. public String toString() {
  1075. return mAddress;
  1076. }
  1077. @Override
  1078. public int describeContents() {
  1079. return 0;
  1080. }
  1081. public static final @android.annotation.NonNull Parcelable.Creator<BluetoothDevice> CREATOR =
  1082. new Parcelable.Creator<BluetoothDevice>() {
  1083. public BluetoothDevice createFromParcel(Parcel in) {
  1084. return new BluetoothDevice(in.readString());
  1085. }
  1086. public BluetoothDevice[] newArray(int size) {
  1087. return new BluetoothDevice[size];
  1088. }
  1089. };
  1090. @Override
  1091. public void writeToParcel(Parcel out, int flags) {
  1092. out.writeString(mAddress);
  1093. }
  1094. /**
  1095. * Returns the hardware address of this BluetoothDevice.
  1096. * <p> For example, "00:11:22:AA:BB:CC".
  1097. *
  1098. * @return Bluetooth hardware address as string
  1099. */
  1100. public String getAddress() {
  1101. if (DBG) Log.d(TAG, "mAddress: " + mAddress);
  1102. return mAddress;
  1103. }
  1104. /**
  1105. * Returns the anonymized hardware address of this BluetoothDevice. The first three octets
  1106. * will be suppressed for anonymization.
  1107. * <p> For example, "XX:XX:XX:AA:BB:CC".
  1108. *
  1109. * @return Anonymized bluetooth hardware address as string
  1110. * @hide
  1111. */
  1112. public String getAnonymizedAddress() {
  1113. return "XX:XX:XX" + getAddress().substring(8);
  1114. }
  1115. /**
  1116. * Get the friendly Bluetooth name of the remote device.
  1117. *
  1118. * <p>The local adapter will automatically retrieve remote names when
  1119. * performing a device scan, and will cache them. This method just returns
  1120. * the name for this device from the cache.
  1121. *
  1122. * @return the Bluetooth name, or null if there was a problem.
  1123. */
  1124. @RequiresLegacyBluetoothPermission
  1125. @RequiresBluetoothConnectPermission
  1126. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  1127. public String getName() {
  1128. final IBluetooth service = sService;
  1129. if (service == null) {
  1130. Log.e(TAG, "BT not enabled. Cannot get Remote Device name");
  1131. return null;
  1132. }
  1133. try {
  1134. String name = service.getRemoteName(this, mAttributionSource);
  1135. if (name != null) {
  1136. // remove whitespace characters from the name
  1137. return name
  1138. .replace('\t', ' ')
  1139. .replace('\n', ' ')
  1140. .replace('\r', ' ');
  1141. }
  1142. return null;
  1143. } catch (RemoteException e) {
  1144. Log.e(TAG, "", e);
  1145. }
  1146. return null;
  1147. }
  1148. /**
  1149. * Get the Bluetooth device type of the remote device.
  1150. *
  1151. * @return the device type {@link #DEVICE_TYPE_CLASSIC}, {@link #DEVICE_TYPE_LE} {@link
  1152. * #DEVICE_TYPE_DUAL}. {@link #DEVICE_TYPE_UNKNOWN} if it's not available
  1153. */
  1154. @RequiresLegacyBluetoothPermission
  1155. @RequiresBluetoothConnectPermission
  1156. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  1157. public int getType() {
  1158. final IBluetooth service = sService;
  1159. if (service == null) {
  1160. Log.e(TAG, "BT not enabled. Cannot get Remote Device type");
  1161. return DEVICE_TYPE_UNKNOWN;
  1162. }
  1163. try {
  1164. return service.getRemoteType(this, mAttributionSource);
  1165. } catch (RemoteException e) {
  1166. Log.e(TAG, "", e);
  1167. }
  1168. return DEVICE_TYPE_UNKNOWN;
  1169. }
  1170. /**
  1171. * Get the locally modifiable name (alias) of the remote Bluetooth device.
  1172. *
  1173. * @return the Bluetooth alias, the friendly device name if no alias, or
  1174. * null if there was a problem
  1175. */
  1176. @Nullable
  1177. @RequiresLegacyBluetoothPermission
  1178. @RequiresBluetoothConnectPermission
  1179. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  1180. public String getAlias() {
  1181. final IBluetooth service = sService;
  1182. if (service == null) {
  1183. Log.e(TAG, "BT not enabled. Cannot get Remote Device Alias");
  1184. return null;
  1185. }
  1186. try {
  1187. String alias = service.getRemoteAliasWithAttribution(this, mAttributionSource);
  1188. if (alias == null) {
  1189. return getName();
  1190. }
  1191. return alias
  1192. .replace('\t', ' ')
  1193. .replace('\n', ' ')
  1194. .replace('\r', ' ');
  1195. } catch (RemoteException e) {
  1196. Log.e(TAG, "", e);
  1197. }
  1198. return null;
  1199. }
  1200. /** @hide */
  1201. @Retention(RetentionPolicy.SOURCE)
  1202. @IntDef(value = {
  1203. BluetoothStatusCodes.SUCCESS,
  1204. BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
  1205. BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED,
  1206. BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION,
  1207. BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED
  1208. })
  1209. public @interface SetAliasReturnValues{}
  1210. /**
  1211. * Sets the locally modifiable name (alias) of the remote Bluetooth device. This method
  1212. * overwrites the previously stored alias. The new alias is saved in local
  1213. * storage so that the change is preserved over power cycles.
  1214. *
  1215. * <p>This method requires the calling app to be associated with Companion Device Manager (see
  1216. * {@link android.companion.CompanionDeviceManager#associate(AssociationRequest,
  1217. * android.companion.CompanionDeviceManager.Callback, Handler)}) and have the
  1218. * {@link android.Manifest.permission#BLUETOOTH_CONNECT} permission. Alternatively, if the
  1219. * caller has the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission, they can
  1220. * bypass the Companion Device Manager association requirement as well as other permission
  1221. * requirements.
  1222. *
  1223. * @param alias is the new locally modifiable name for the remote Bluetooth device which must
  1224. * be the empty string. If null, we clear the alias.
  1225. * @return whether the alias was successfully changed
  1226. * @throws IllegalArgumentException if the alias is the empty string
  1227. */
  1228. @RequiresLegacyBluetoothPermission
  1229. @RequiresBluetoothConnectPermission
  1230. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  1231. public @SetAliasReturnValues int setAlias(@Nullable String alias) {
  1232. if (alias != null && alias.isEmpty()) {
  1233. throw new IllegalArgumentException("alias cannot be the empty string");
  1234. }
  1235. final IBluetooth service = sService;
  1236. if (service == null) {
  1237. Log.e(TAG, "BT not enabled. Cannot set Remote Device name");
  1238. return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
  1239. }
  1240. try {
  1241. return service.setRemoteAlias(this, alias, mAttributionSource);
  1242. } catch (RemoteException e) {
  1243. Log.e(TAG, "", e);
  1244. throw e.rethrowFromSystemServer();
  1245. }
  1246. }
  1247. /**
  1248. * Get the most recent identified battery level of this Bluetooth device
  1249. *
  1250. * @return Battery level in percents from 0 to 100, {@link #BATTERY_LEVEL_BLUETOOTH_OFF} if
  1251. * Bluetooth is disabled or {@link #BATTERY_LEVEL_UNKNOWN} if device is disconnected, or does
  1252. * not have any battery reporting service, or return value is invalid
  1253. * @hide
  1254. */
  1255. @UnsupportedAppUsage
  1256. @RequiresLegacyBluetoothPermission
  1257. @RequiresBluetoothConnectPermission
  1258. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  1259. public int getBatteryLevel() {
  1260. final IBluetooth service = sService;
  1261. if (service == null) {
  1262. Log.e(TAG, "Bluetooth disabled. Cannot get remote device battery level");
  1263. return BATTERY_LEVEL_BLUETOOTH_OFF;
  1264. }
  1265. try {
  1266. return service.getBatteryLevel(this, mAttributionSource);
  1267. } catch (RemoteException e) {
  1268. Log.e(TAG, "", e);
  1269. }
  1270. return BATTERY_LEVEL_UNKNOWN;
  1271. }
  1272. /**
  1273. * Start the bonding (pairing) process with the remote device.
  1274. * <p>This is an asynchronous call, it will return immediately. Register
  1275. * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
  1276. * the bonding process completes, and its result.
  1277. * <p>Android system services will handle the necessary user interactions
  1278. * to confirm and complete the bonding process.
  1279. *
  1280. * @return false on immediate error, true if bonding will begin
  1281. */
  1282. @RequiresLegacyBluetoothAdminPermission
  1283. @RequiresBluetoothConnectPermission
  1284. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  1285. public boolean createBond() {
  1286. return createBond(TRANSPORT_AUTO);
  1287. }
  1288. /**
  1289. * Start the bonding (pairing) process with the remote device using the
  1290. * specified transport.
  1291. *
  1292. * <p>This is an asynchronous call, it will return immediately. Register
  1293. * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
  1294. * the bonding process completes, and its result.
  1295. * <p>Android system services will handle the necessary user interactions
  1296. * to confirm and complete the bonding process.
  1297. *
  1298. * @param transport The transport to use for the pairing procedure.
  1299. * @return false on immediate error, true if bonding will begin
  1300. * @throws IllegalArgumentException if an invalid transport was specified
  1301. * @hide
  1302. */
  1303. @SystemApi
  1304. @RequiresLegacyBluetoothAdminPermission
  1305. @RequiresBluetoothConnectPermission
  1306. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  1307. public boolean createBond(int transport) {
  1308. return createBondInternal(transport, null, null);
  1309. }
  1310. /**
  1311. * Start the bonding (pairing) process with the remote device using the
  1312. * Out Of Band mechanism.
  1313. *
  1314. * <p>This is an asynchronous call, it will return immediately. Register
  1315. * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
  1316. * the bonding process completes, and its result.
  1317. *
  1318. * <p>Android system services will handle the necessary user interactions
  1319. * to confirm and complete the bonding process.
  1320. *
  1321. * <p>There are two possible versions of OOB Data. This data can come in as
  1322. * P192 or P256. This is a reference to the cryptography used to generate the key.
  1323. * The caller may pass one or both. If both types of data are passed, then the
  1324. * P256 data will be preferred, and thus used.
  1325. *
  1326. * @param transport - Transport to use
  1327. * @param remoteP192Data - Out Of Band data (P192) or null
  1328. * @param remoteP256Data - Out Of Band data (P256) or null
  1329. * @return false on immediate error, true if bonding will begin
  1330. * @hide
  1331. */
  1332. @SystemApi
  1333. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  1334. public boolean createBondOutOfBand(int transport, @Nullable OobData remoteP192Data,
  1335. @Nullable OobData remoteP256Data) {
  1336. if (remoteP192Data == null && remoteP256Data == null) {
  1337. throw new IllegalArgumentException(
  1338. "One or both arguments for the OOB data types are required to not be null."
  1339. + " Please use createBond() instead if you do not have OOB data to pass.");
  1340. }
  1341. return createBondInternal(transport, remoteP192Data, remoteP256Data);
  1342. }
  1343. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  1344. private boolean createBondInternal(int transport, @Nullable OobData remoteP192Data,
  1345. @Nullable OobData remoteP256Data) {
  1346. final IBluetooth service = sService;
  1347. if (service == null) {
  1348. Log.w(TAG, "BT not enabled, createBondOutOfBand failed");
  1349. return false;
  1350. }
  1351. if (NULL_MAC_ADDRESS.equals(mAddress)) {
  1352. Log.e(TAG, "Unable to create bond, invalid address " + mAddress);
  1353. return false;
  1354. }
  1355. try {
  1356. return service.createBond(
  1357. this, transport, remoteP192Data, remoteP256Data, mAttributionSource);
  1358. } catch (RemoteException e) {
  1359. Log.e(TAG, "", e);
  1360. }
  1361. return false;
  1362. }
  1363. /**
  1364. * Gets whether bonding was initiated locally
  1365. *
  1366. * @return true if bonding is initiated locally, false otherwise
  1367. *
  1368. * @hide
  1369. */
  1370. @UnsupportedAppUsage
  1371. @RequiresLegacyBluetoothPermission
  1372. @RequiresBluetoothConnectPermission
  1373. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  1374. public boolean isBondingInitiatedLocally() {
  1375. final IBluetooth service = sService;
  1376. if (service == null) {
  1377. Log.w(TAG, "BT not enabled, isBondingInitiatedLocally failed");
  1378. return false;
  1379. }
  1380. try {
  1381. return service.isBondingInitiatedLocally(this, mAttributionSource);
  1382. } catch (RemoteException e) {
  1383. Log.e(TAG, "", e);
  1384. }
  1385. return false;
  1386. }
  1387. /**
  1388. * Cancel an in-progress bonding request started with {@link #createBond}.
  1389. *
  1390. * @return true on success, false on error
  1391. * @hide
  1392. */
  1393. @SystemApi
  1394. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  1395. public boolean cancelBondProcess() {
  1396. final IBluetooth service = sService;
  1397. if (service == null) {
  1398. Log.e(TAG, "BT not enabled. Cannot cancel Remote Device bond");
  1399. return false;
  1400. }
  1401. try {
  1402. Log.i(TAG, "cancelBondProcess() for device " + getAddress()
  1403. + " called by pid: " + Process.myPid()
  1404. + " tid: " + Process.myTid());
  1405. return service.cancelBondProcess(this, mAttributionSource);
  1406. } catch (RemoteException e) {
  1407. Log.e(TAG, "", e);
  1408. }
  1409. return false;
  1410. }
  1411. /**
  1412. * Remove bond (pairing) with the remote device.
  1413. * <p>Delete the link key associated with the remote device, and
  1414. * immediately terminate connections to that device that require
  1415. * authentication and encryption.
  1416. *
  1417. * @return true on success, false on error
  1418. * @hide
  1419. */
  1420. @SystemApi
  1421. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  1422. public boolean removeBond() {
  1423. final IBluetooth service = sService;
  1424. if (service == null) {
  1425. Log.e(TAG, "BT not enabled. Cannot remove Remote Device bond");
  1426. return false;
  1427. }
  1428. try {
  1429. Log.i(TAG, "removeBond() for device " + getAddress()
  1430. + " called by pid: " + Process.myPid()
  1431. + " tid: " + Process.myTid());
  1432. return service.removeBond(this, mAttributionSource);
  1433. } catch (RemoteException e) {
  1434. Log.e(TAG, "", e);
  1435. }
  1436. return false;
  1437. }
  1438. private static final String BLUETOOTH_BONDING_CACHE_PROPERTY =
  1439. "cache_key.bluetooth.get_bond_state";
  1440. private final PropertyInvalidatedCache<BluetoothDevice, Integer> mBluetoothBondCache =
  1441. new PropertyInvalidatedCache<BluetoothDevice, Integer>(
  1442. 8, BLUETOOTH_BONDING_CACHE_PROPERTY) {
  1443. @Override
  1444. @SuppressLint("AndroidFrameworkRequiresPermission")
  1445. protected Integer recompute(BluetoothDevice query) {
  1446. try {
  1447. return sService.getBondState(query, mAttributionSource);
  1448. } catch (RemoteException e) {
  1449. throw e.rethrowAsRuntimeException();
  1450. }
  1451. }
  1452. };
  1453. /** @hide */
  1454. public void disableBluetoothGetBondStateCache() {
  1455. mBluetoothBondCache.disableLocal();
  1456. }
  1457. /** @hide */
  1458. public static void invalidateBluetoothGetBondStateCache() {
  1459. PropertyInvalidatedCache.invalidateCache(BLUETOOTH_BONDING_CACHE_PROPERTY);
  1460. }
  1461. /**
  1462. * Get the bond state of the remote device.
  1463. * <p>Possible values for the bond state are:
  1464. * {@link #BOND_NONE},
  1465. * {@link #BOND_BONDING},
  1466. * {@link #BOND_BONDED}.
  1467. *
  1468. * @return the bond state
  1469. */
  1470. @RequiresLegacyBluetoothPermission
  1471. @RequiresBluetoothConnectPermission
  1472. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  1473. @SuppressLint("AndroidFrameworkRequiresPermission")
  1474. public int getBondState() {
  1475. final IBluetooth service = sService;
  1476. if (service == null) {
  1477. Log.e(TAG, "BT not enabled. Cannot get bond state");
  1478. return BOND_NONE;
  1479. }
  1480. try {
  1481. return mBluetoothBondCache.query(this);
  1482. } catch (RuntimeException e) {
  1483. if (e.getCause() instanceof RemoteException) {
  1484. Log.e(TAG, "", e);
  1485. } else {
  1486. throw e;
  1487. }
  1488. }
  1489. return BOND_NONE;
  1490. }
  1491. /**
  1492. * Checks whether this bluetooth device is associated with CDM and meets the criteria to skip
  1493. * the bluetooth pairing dialog because it has been already consented by the CDM prompt.
  1494. *
  1495. * @return true if we can bond without the dialog, false otherwise
  1496. *
  1497. * @hide
  1498. */
  1499. @SystemApi
  1500. @RequiresPermission(allOf = {
  1501. android.Manifest.permission.BLUETOOTH_CONNECT,
  1502. android.Manifest.permission.BLUETOOTH_PRIVILEGED,
  1503. })
  1504. public boolean canBondWithoutDialog() {
  1505. final IBluetooth service = sService;
  1506. if (service == null) {
  1507. Log.e(TAG, "BT not enabled. Cannot check if we can skip pairing dialog");
  1508. return false;
  1509. }
  1510. try {
  1511. if (DBG) Log.d(TAG, "canBondWithoutDialog, device: " + this);
  1512. return service.canBondWithoutDialog(this, mAttributionSource);
  1513. } catch (RemoteException e) {
  1514. Log.e(TAG, "", e);
  1515. }
  1516. return false;
  1517. }
  1518. /** @hide */
  1519. @Retention(RetentionPolicy.SOURCE)
  1520. @IntDef(value = {
  1521. BluetoothStatusCodes.SUCCESS,
  1522. BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
  1523. BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED,
  1524. BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION,
  1525. BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED
  1526. })
  1527. public @interface ConnectionReturnValues{}
  1528. /**
  1529. * Connects all user enabled and supported bluetooth profiles between the local and remote
  1530. * device. If no profiles are user enabled (e.g. first connection), we connect all supported
  1531. * profiles. If the device is not already connected, this will page the device before initiating
  1532. * profile connections. Connection is asynchronous and you should listen to each profile's
  1533. * broadcast intent ACTION_CONNECTION_STATE_CHANGED to verify whether connection was successful.
  1534. * For example, to verify a2dp is connected, you would listen for
  1535. * {@link BluetoothA2dp#ACTION_CONNECTION_STATE_CHANGED}
  1536. *
  1537. * @return whether the messages were successfully sent to try to connect all profiles
  1538. * @throws IllegalArgumentException if the device address is invalid
  1539. *
  1540. * @hide
  1541. */
  1542. @SystemApi
  1543. @RequiresBluetoothConnectPermission
  1544. @RequiresPermission(allOf = {
  1545. android.Manifest.permission.BLUETOOTH_CONNECT,
  1546. android.Manifest.permission.BLUETOOTH_PRIVILEGED,
  1547. android.Manifest.permission.MODIFY_PHONE_STATE,
  1548. })
  1549. public @ConnectionReturnValues int connect() {
  1550. if (!BluetoothAdapter.checkBluetoothAddress(getAddress())) {
  1551. throw new IllegalArgumentException("device cannot have an invalid address");
  1552. }
  1553. try {
  1554. if (sService == null) {
  1555. Log.e(TAG, "BT not enabled. Cannot connect to remote device.");
  1556. return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
  1557. }
  1558. return sService.connectAllEnabledProfiles(this, mAttributionSource);
  1559. } catch (RemoteException e) {
  1560. Log.e(TAG, "", e);
  1561. throw e.rethrowFromSystemServer();
  1562. }
  1563. }
  1564. /**
  1565. * Disconnects all connected bluetooth profiles between the local and remote device.
  1566. * Disconnection is asynchronous and you should listen to each profile's broadcast intent
  1567. * ACTION_CONNECTION_STATE_CHANGED to verify whether disconnection was successful. For example,
  1568. * to verify a2dp is disconnected, you would listen for
  1569. * {@link BluetoothA2dp#ACTION_CONNECTION_STATE_CHANGED}
  1570. *
  1571. * @return whether the messages were successfully sent to try to disconnect all profiles
  1572. * @throws IllegalArgumentException if the device address is invalid
  1573. *
  1574. * @hide
  1575. */
  1576. @SystemApi
  1577. @RequiresBluetoothConnectPermission
  1578. @RequiresPermission(allOf = {
  1579. android.Manifest.permission.BLUETOOTH_CONNECT,
  1580. android.Manifest.permission.BLUETOOTH_PRIVILEGED,
  1581. })
  1582. public @ConnectionReturnValues int disconnect() {
  1583. if (!BluetoothAdapter.checkBluetoothAddress(getAddress())) {
  1584. throw new IllegalArgumentException("device cannot have an invalid address");
  1585. }
  1586. try {
  1587. if (sService == null) {
  1588. Log.e(TAG, "BT not enabled. Cannot disconnect from remote device.");
  1589. return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
  1590. }
  1591. return sService.disconnectAllEnabledProfiles(this, mAttributionSource);
  1592. } catch (RemoteException e) {
  1593. Log.e(TAG, "", e);
  1594. throw e.rethrowFromSystemServer();
  1595. }
  1596. }
  1597. /**
  1598. * Returns whether there is an open connection to this device.
  1599. *
  1600. * @return True if there is at least one open connection to this device.
  1601. * @hide
  1602. */
  1603. @SystemApi
  1604. @RequiresLegacyBluetoothPermission
  1605. @RequiresBluetoothConnectPermission
  1606. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  1607. public boolean isConnected() {
  1608. final IBluetooth service = sService;
  1609. if (service == null) {
  1610. // BT is not enabled, we cannot be connected.
  1611. return false;
  1612. }
  1613. try {
  1614. return service.getConnectionStateWithAttribution(this, mAttributionSource)
  1615. != CONNECTION_STATE_DISCONNECTED;
  1616. } catch (RemoteException e) {
  1617. Log.e(TAG, "", e);
  1618. return false;
  1619. }
  1620. }
  1621. /**
  1622. * Returns whether there is an open connection to this device
  1623. * that has been encrypted.
  1624. *
  1625. * @return True if there is at least one encrypted connection to this device.
  1626. * @hide
  1627. */
  1628. @SystemApi
  1629. @RequiresLegacyBluetoothPermission
  1630. @RequiresBluetoothConnectPermission
  1631. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  1632. public boolean isEncrypted() {
  1633. final IBluetooth service = sService;
  1634. if (service == null) {
  1635. // BT is not enabled, we cannot be connected.
  1636. return false;
  1637. }
  1638. try {
  1639. return service.getConnectionStateWithAttribution(this, mAttributionSource)
  1640. > CONNECTION_STATE_CONNECTED;
  1641. } catch (RemoteException e) {
  1642. Log.e(TAG, "", e);
  1643. return false;
  1644. }
  1645. }
  1646. /**
  1647. * Get the Bluetooth class of the remote device.
  1648. *
  1649. * @return Bluetooth class object, or null on error
  1650. */
  1651. @RequiresLegacyBluetoothPermission
  1652. @RequiresBluetoothConnectPermission
  1653. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  1654. public BluetoothClass getBluetoothClass() {
  1655. final IBluetooth service = sService;
  1656. if (service == null) {
  1657. Log.e(TAG, "BT not enabled. Cannot get Bluetooth Class");
  1658. return null;
  1659. }
  1660. try {
  1661. int classInt = service.getRemoteClass(this, mAttributionSource);
  1662. if (classInt == BluetoothClass.ERROR) return null;
  1663. return new BluetoothClass(classInt);
  1664. } catch (RemoteException e) {
  1665. Log.e(TAG, "", e);
  1666. }
  1667. return null;
  1668. }
  1669. /**
  1670. * Returns the supported features (UUIDs) of the remote device.
  1671. *
  1672. * <p>This method does not start a service discovery procedure to retrieve the UUIDs
  1673. * from the remote device. Instead, the local cached copy of the service
  1674. * UUIDs are returned.
  1675. * <p>Use {@link #fetchUuidsWithSdp} if fresh UUIDs are desired.
  1676. *
  1677. * @return the supported features (UUIDs) of the remote device, or null on error
  1678. */
  1679. @RequiresLegacyBluetoothPermission
  1680. @RequiresBluetoothConnectPermission
  1681. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  1682. public ParcelUuid[] getUuids() {
  1683. final IBluetooth service = sService;
  1684. if (service == null || !isBluetoothEnabled()) {
  1685. Log.e(TAG, "BT not enabled. Cannot get remote device Uuids");
  1686. return null;
  1687. }
  1688. try {
  1689. return service.getRemoteUuids(this, mAttributionSource);
  1690. } catch (RemoteException e) {
  1691. Log.e(TAG, "", e);
  1692. }
  1693. return null;
  1694. }
  1695. /**
  1696. * Perform a service discovery on the remote device to get the UUIDs supported.
  1697. *
  1698. * <p>This API is asynchronous and {@link #ACTION_UUID} intent is sent,
  1699. * with the UUIDs supported by the remote end. If there is an error
  1700. * in getting the SDP records or if the process takes a long time, or the device is bonding and
  1701. * we have its UUIDs cached, {@link #ACTION_UUID} intent is sent with the UUIDs that is
  1702. * currently present in the cache. Clients should use the {@link #getUuids} to get UUIDs
  1703. * if service discovery is not to be performed. If there is an ongoing bonding process,
  1704. * service discovery or device inquiry, the request will be queued.
  1705. *
  1706. * @return False if the check fails, True if the process of initiating an ACL connection
  1707. * to the remote device was started or cached UUIDs will be broadcast.
  1708. */
  1709. @RequiresLegacyBluetoothPermission
  1710. @RequiresBluetoothConnectPermission
  1711. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  1712. public boolean fetchUuidsWithSdp() {
  1713. return fetchUuidsWithSdp(TRANSPORT_AUTO);
  1714. }
  1715. /**
  1716. * Perform a service discovery on the remote device to get the UUIDs supported with the
  1717. * specific transport.
  1718. *
  1719. * <p>This API is asynchronous and {@link #ACTION_UUID} intent is sent,
  1720. * with the UUIDs supported by the remote end. If there is an error
  1721. * in getting the SDP or GATT records or if the process takes a long time, or the device
  1722. * is bonding and we have its UUIDs cached, {@link #ACTION_UUID} intent is sent with the
  1723. * UUIDs that is currently present in the cache. Clients should use the {@link #getUuids}
  1724. * to get UUIDs if service discovery is not to be performed. If there is an ongoing bonding
  1725. * process, service discovery or device inquiry, the request will be queued.
  1726. *
  1727. * @param transport - provide type of transport (e.g. LE or Classic).
  1728. * @return False if the check fails, True if the process of initiating an ACL connection
  1729. * to the remote device was started or cached UUIDs will be broadcast with the specific
  1730. * transport.
  1731. *
  1732. * @hide
  1733. */
  1734. @SystemApi
  1735. @RequiresPermission(allOf = {
  1736. android.Manifest.permission.BLUETOOTH_CONNECT,
  1737. android.Manifest.permission.BLUETOOTH_PRIVILEGED,
  1738. })
  1739. public boolean fetchUuidsWithSdp(@Transport int transport) {
  1740. final IBluetooth service = sService;
  1741. if (service == null || !isBluetoothEnabled()) {
  1742. Log.e(TAG, "BT not enabled. Cannot fetchUuidsWithSdp");
  1743. return false;
  1744. }
  1745. try {
  1746. return service.fetchRemoteUuidsWithAttribution(this, transport, mAttributionSource);
  1747. } catch (RemoteException e) {
  1748. Log.e(TAG, "", e);
  1749. }
  1750. return false;
  1751. }
  1752. /**
  1753. * Perform a service discovery on the remote device to get the SDP records associated
  1754. * with the specified UUID.
  1755. *
  1756. * <p>This API is asynchronous and {@link #ACTION_SDP_RECORD} intent is sent,
  1757. * with the SDP records found on the remote end. If there is an error
  1758. * in getting the SDP records or if the process takes a long time,
  1759. * {@link #ACTION_SDP_RECORD} intent is sent with an status value in
  1760. * {@link #EXTRA_SDP_SEARCH_STATUS} different from 0.
  1761. * Detailed status error codes can be found by members of the Bluetooth package in
  1762. * the AbstractionLayer class.
  1763. * <p>The SDP record data will be stored in the intent as {@link #EXTRA_SDP_RECORD}.
  1764. * The object type will match one of the SdpXxxRecord types, depending on the UUID searched
  1765. * for.
  1766. *
  1767. * @return False if the check fails, True if the process
  1768. * of initiating an ACL connection to the remote device
  1769. * was started.
  1770. */
  1771. /** @hide */
  1772. @RequiresLegacyBluetoothPermission
  1773. @RequiresBluetoothConnectPermission
  1774. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  1775. public boolean sdpSearch(ParcelUuid uuid) {
  1776. final IBluetooth service = sService;
  1777. if (service == null) {
  1778. Log.e(TAG, "BT not enabled. Cannot query remote device sdp records");
  1779. return false;
  1780. }
  1781. try {
  1782. return service.sdpSearch(this, uuid, mAttributionSource);
  1783. } catch (RemoteException e) {
  1784. Log.e(TAG, "", e);
  1785. }
  1786. return false;
  1787. }
  1788. /**
  1789. * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN}
  1790. *
  1791. * @return true pin has been set false for error
  1792. */
  1793. @RequiresLegacyBluetoothAdminPermission
  1794. @RequiresBluetoothConnectPermission
  1795. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  1796. public boolean setPin(byte[] pin) {
  1797. final IBluetooth service = sService;
  1798. if (service == null) {
  1799. Log.e(TAG, "BT not enabled. Cannot set Remote Device pin");
  1800. return false;
  1801. }
  1802. try {
  1803. return service.setPin(this, true, pin.length, pin, mAttributionSource);
  1804. } catch (RemoteException e) {
  1805. Log.e(TAG, "", e);
  1806. }
  1807. return false;
  1808. }
  1809. /**
  1810. * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN}
  1811. *
  1812. * @return true pin has been set false for error
  1813. * @hide
  1814. */
  1815. @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
  1816. @RequiresLegacyBluetoothAdminPermission
  1817. @RequiresBluetoothConnectPermission
  1818. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  1819. public boolean setPin(@NonNull String pin) {
  1820. byte[] pinBytes = convertPinToBytes(pin);
  1821. if (pinBytes == null) {
  1822. return false;
  1823. }
  1824. return setPin(pinBytes);
  1825. }
  1826. /**
  1827. * Confirm passkey for {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION} pairing.
  1828. *
  1829. * @return true confirmation has been sent out false for error
  1830. */
  1831. @RequiresPermission(allOf = {
  1832. android.Manifest.permission.BLUETOOTH_CONNECT,
  1833. android.Manifest.permission.BLUETOOTH_PRIVILEGED,
  1834. })
  1835. public boolean setPairingConfirmation(boolean confirm) {
  1836. final IBluetooth service = sService;
  1837. if (service == null) {
  1838. Log.e(TAG, "BT not enabled. Cannot set pairing confirmation");
  1839. return false;
  1840. }
  1841. try {
  1842. return service.setPairingConfirmation(this, confirm, mAttributionSource);
  1843. } catch (RemoteException e) {
  1844. Log.e(TAG, "", e);
  1845. }
  1846. return false;
  1847. }
  1848. /**
  1849. * Cancels pairing to this device
  1850. *
  1851. * @return true if pairing cancelled successfully, false otherwise
  1852. *
  1853. * @hide
  1854. */
  1855. @UnsupportedAppUsage
  1856. @RequiresLegacyBluetoothAdminPermission
  1857. @RequiresBluetoothConnectPermission
  1858. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  1859. public boolean cancelPairing() {
  1860. final IBluetooth service = sService;
  1861. if (service == null) {
  1862. Log.e(TAG, "BT not enabled. Cannot cancel pairing");
  1863. return false;
  1864. }
  1865. try {
  1866. return service.cancelBondProcess(this, mAttributionSource);
  1867. } catch (RemoteException e) {
  1868. Log.e(TAG, "", e);
  1869. }
  1870. return false;
  1871. }
  1872. boolean isBluetoothEnabled() {
  1873. boolean ret = false;
  1874. BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
  1875. if (adapter != null && adapter.isEnabled()) {
  1876. ret = true;
  1877. }
  1878. return ret;
  1879. }
  1880. /**
  1881. * Gets whether the phonebook access is allowed for this bluetooth device
  1882. *
  1883. * @return Whether the phonebook access is allowed to this device. Can be {@link
  1884. * #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
  1885. * @hide
  1886. */
  1887. @UnsupportedAppUsage
  1888. @RequiresLegacyBluetoothPermission
  1889. @RequiresBluetoothConnectPermission
  1890. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  1891. public @AccessPermission int getPhonebookAccessPermission() {
  1892. final IBluetooth service = sService;
  1893. if (service == null) {
  1894. return ACCESS_UNKNOWN;
  1895. }
  1896. try {
  1897. return service.getPhonebookAccessPermission(this, mAttributionSource);
  1898. } catch (RemoteException e) {
  1899. Log.e(TAG, "", e);
  1900. }
  1901. return ACCESS_UNKNOWN;
  1902. }
  1903. /**
  1904. * Sets whether the {@link BluetoothDevice} enters silence mode. Audio will not
  1905. * be routed to the {@link BluetoothDevice} if set to {@code true}.
  1906. *
  1907. * When the {@link BluetoothDevice} enters silence mode, and the {@link BluetoothDevice}
  1908. * is an active device (for A2DP or HFP), the active device for that profile
  1909. * will be set to null.
  1910. * If the {@link BluetoothDevice} exits silence mode while the A2DP or HFP
  1911. * active device is null, the {@link BluetoothDevice} will be set as the
  1912. * active device for that profile.
  1913. * If the {@link BluetoothDevice} is disconnected, it exits silence mode.
  1914. * If the {@link BluetoothDevice} is set as the active device for A2DP or
  1915. * HFP, while silence mode is enabled, then the device will exit silence mode.
  1916. * If the {@link BluetoothDevice} is in silence mode, AVRCP position change
  1917. * event and HFP AG indicators will be disabled.
  1918. * If the {@link BluetoothDevice} is not connected with A2DP or HFP, it cannot
  1919. * enter silence mode.
  1920. *
  1921. * @param silence true to enter silence mode, false to exit
  1922. * @return true on success, false on error.
  1923. * @throws IllegalStateException if Bluetooth is not turned ON.
  1924. * @hide
  1925. */
  1926. @SystemApi
  1927. @RequiresPermission(allOf = {
  1928. android.Manifest.permission.BLUETOOTH_CONNECT,
  1929. android.Manifest.permission.BLUETOOTH_PRIVILEGED,
  1930. })
  1931. public boolean setSilenceMode(boolean silence) {
  1932. final IBluetooth service = sService;
  1933. if (service == null) {
  1934. throw new IllegalStateException("Bluetooth is not turned ON");
  1935. }
  1936. try {
  1937. return service.setSilenceMode(this, silence, mAttributionSource);
  1938. } catch (RemoteException e) {
  1939. Log.e(TAG, "setSilenceMode fail", e);
  1940. return false;
  1941. }
  1942. }
  1943. /**
  1944. * Check whether the {@link BluetoothDevice} is in silence mode
  1945. *
  1946. * @return true on device in silence mode, otherwise false.
  1947. * @throws IllegalStateException if Bluetooth is not turned ON.
  1948. * @hide
  1949. */
  1950. @SystemApi
  1951. @RequiresPermission(allOf = {
  1952. android.Manifest.permission.BLUETOOTH_CONNECT,
  1953. android.Manifest.permission.BLUETOOTH_PRIVILEGED,
  1954. })
  1955. public boolean isInSilenceMode() {
  1956. final IBluetooth service = sService;
  1957. if (service == null) {
  1958. throw new IllegalStateException("Bluetooth is not turned ON");
  1959. }
  1960. try {
  1961. return service.getSilenceMode(this, mAttributionSource);
  1962. } catch (RemoteException e) {
  1963. Log.e(TAG, "isInSilenceMode fail", e);
  1964. return false;
  1965. }
  1966. }
  1967. /**
  1968. * Sets whether the phonebook access is allowed to this device.
  1969. *
  1970. * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link
  1971. * #ACCESS_REJECTED}.
  1972. * @return Whether the value has been successfully set.
  1973. * @hide
  1974. */
  1975. @SystemApi
  1976. @RequiresPermission(allOf = {
  1977. android.Manifest.permission.BLUETOOTH_CONNECT,
  1978. android.Manifest.permission.BLUETOOTH_PRIVILEGED,
  1979. })
  1980. public boolean setPhonebookAccessPermission(@AccessPermission int value) {
  1981. final IBluetooth service = sService;
  1982. if (service == null) {
  1983. return false;
  1984. }
  1985. try {
  1986. return service.setPhonebookAccessPermission(this, value, mAttributionSource);
  1987. } catch (RemoteException e) {
  1988. Log.e(TAG, "", e);
  1989. }
  1990. return false;
  1991. }
  1992. /**
  1993. * Gets whether message access is allowed to this bluetooth device
  1994. *
  1995. * @return Whether the message access is allowed to this device.
  1996. * @hide
  1997. */
  1998. @UnsupportedAppUsage
  1999. @RequiresLegacyBluetoothPermission
  2000. @RequiresBluetoothConnectPermission
  2001. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  2002. public @AccessPermission int getMessageAccessPermission() {
  2003. final IBluetooth service = sService;
  2004. if (service == null) {
  2005. return ACCESS_UNKNOWN;
  2006. }
  2007. try {
  2008. return service.getMessageAccessPermission(this, mAttributionSource);
  2009. } catch (RemoteException e) {
  2010. Log.e(TAG, "", e);
  2011. }
  2012. return ACCESS_UNKNOWN;
  2013. }
  2014. /**
  2015. * Sets whether the message access is allowed to this device.
  2016. *
  2017. * @param value Can be {@link #ACCESS_UNKNOWN} if the device is unbonded,
  2018. * {@link #ACCESS_ALLOWED} if the permission is being granted, or {@link #ACCESS_REJECTED} if
  2019. * the permission is not being granted.
  2020. * @return Whether the value has been successfully set.
  2021. * @hide
  2022. */
  2023. @SystemApi
  2024. @RequiresPermission(allOf = {
  2025. android.Manifest.permission.BLUETOOTH_CONNECT,
  2026. android.Manifest.permission.BLUETOOTH_PRIVILEGED,
  2027. })
  2028. public boolean setMessageAccessPermission(@AccessPermission int value) {
  2029. // Validates param value is one of the accepted constants
  2030. if (value != ACCESS_ALLOWED && value != ACCESS_REJECTED && value != ACCESS_UNKNOWN) {
  2031. throw new IllegalArgumentException(value + "is not a valid AccessPermission value");
  2032. }
  2033. final IBluetooth service = sService;
  2034. if (service == null) {
  2035. return false;
  2036. }
  2037. try {
  2038. return service.setMessageAccessPermission(this, value, mAttributionSource);
  2039. } catch (RemoteException e) {
  2040. Log.e(TAG, "", e);
  2041. }
  2042. return false;
  2043. }
  2044. /**
  2045. * Gets whether sim access is allowed for this bluetooth device
  2046. *
  2047. * @return Whether the Sim access is allowed to this device.
  2048. * @hide
  2049. */
  2050. @SystemApi
  2051. @RequiresLegacyBluetoothPermission
  2052. @RequiresBluetoothConnectPermission
  2053. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  2054. public @AccessPermission int getSimAccessPermission() {
  2055. final IBluetooth service = sService;
  2056. if (service == null) {
  2057. return ACCESS_UNKNOWN;
  2058. }
  2059. try {
  2060. return service.getSimAccessPermission(this, mAttributionSource);
  2061. } catch (RemoteException e) {
  2062. Log.e(TAG, "", e);
  2063. }
  2064. return ACCESS_UNKNOWN;
  2065. }
  2066. /**
  2067. * Sets whether the Sim access is allowed to this device.
  2068. *
  2069. * @param value Can be {@link #ACCESS_UNKNOWN} if the device is unbonded,
  2070. * {@link #ACCESS_ALLOWED} if the permission is being granted, or {@link #ACCESS_REJECTED} if
  2071. * the permission is not being granted.
  2072. * @return Whether the value has been successfully set.
  2073. * @hide
  2074. */
  2075. @SystemApi
  2076. @RequiresPermission(allOf = {
  2077. android.Manifest.permission.BLUETOOTH_CONNECT,
  2078. android.Manifest.permission.BLUETOOTH_PRIVILEGED,
  2079. })
  2080. public boolean setSimAccessPermission(int value) {
  2081. final IBluetooth service = sService;
  2082. if (service == null) {
  2083. return false;
  2084. }
  2085. try {
  2086. return service.setSimAccessPermission(this, value, mAttributionSource);
  2087. } catch (RemoteException e) {
  2088. Log.e(TAG, "", e);
  2089. }
  2090. return false;
  2091. }
  2092. /**
  2093. * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
  2094. * outgoing connection to this remote device on given channel.
  2095. * <p>The remote device will be authenticated and communication on this
  2096. * socket will be encrypted.
  2097. * <p> Use this socket only if an authenticated socket link is possible.
  2098. * Authentication refers to the authentication of the link key to
  2099. * prevent person-in-the-middle type of attacks.
  2100. * For example, for Bluetooth 2.1 devices, if any of the devices does not
  2101. * have an input and output capability or just has the ability to
  2102. * display a numeric key, a secure socket connection is not possible.
  2103. * In such a case, use {@link createInsecureRfcommSocket}.
  2104. * For more details, refer to the Security Model section 5.2 (vol 3) of
  2105. * Bluetooth Core Specification version 2.1 + EDR.
  2106. * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
  2107. * connection.
  2108. * <p>Valid RFCOMM channels are in range 1 to 30.
  2109. *
  2110. * @param channel RFCOMM channel to connect to
  2111. * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
  2112. * @throws IOException on error, for example Bluetooth not available, or insufficient
  2113. * permissions
  2114. * @hide
  2115. */
  2116. @UnsupportedAppUsage
  2117. @RequiresLegacyBluetoothPermission
  2118. @RequiresBluetoothConnectPermission
  2119. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  2120. @SuppressLint("AndroidFrameworkRequiresPermission")
  2121. public BluetoothSocket createRfcommSocket(int channel) throws IOException {
  2122. if (!isBluetoothEnabled()) {
  2123. Log.e(TAG, "Bluetooth is not enabled");
  2124. throw new IOException();
  2125. }
  2126. return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, channel,
  2127. null);
  2128. }
  2129. /**
  2130. * Create an L2cap {@link BluetoothSocket} ready to start a secure
  2131. * outgoing connection to this remote device on given channel.
  2132. * <p>The remote device will be authenticated and communication on this
  2133. * socket will be encrypted.
  2134. * <p> Use this socket only if an authenticated socket link is possible.
  2135. * Authentication refers to the authentication of the link key to
  2136. * prevent person-in-the-middle type of attacks.
  2137. * For example, for Bluetooth 2.1 devices, if any of the devices does not
  2138. * have an input and output capability or just has the ability to
  2139. * display a numeric key, a secure socket connection is not possible.
  2140. * In such a case, use {@link createInsecureRfcommSocket}.
  2141. * For more details, refer to the Security Model section 5.2 (vol 3) of
  2142. * Bluetooth Core Specification version 2.1 + EDR.
  2143. * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
  2144. * connection.
  2145. * <p>Valid L2CAP PSM channels are in range 1 to 2^16.
  2146. *
  2147. * @param channel L2cap PSM/channel to connect to
  2148. * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
  2149. * @throws IOException on error, for example Bluetooth not available, or insufficient
  2150. * permissions
  2151. * @hide
  2152. */
  2153. @RequiresLegacyBluetoothPermission
  2154. @RequiresBluetoothConnectPermission
  2155. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  2156. @SuppressLint("AndroidFrameworkRequiresPermission")
  2157. public BluetoothSocket createL2capSocket(int channel) throws IOException {
  2158. return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, true, true, this, channel,
  2159. null);
  2160. }
  2161. /**
  2162. * Create an L2cap {@link BluetoothSocket} ready to start an insecure
  2163. * outgoing connection to this remote device on given channel.
  2164. * <p>The remote device will be not authenticated and communication on this
  2165. * socket will not be encrypted.
  2166. * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
  2167. * connection.
  2168. * <p>Valid L2CAP PSM channels are in range 1 to 2^16.
  2169. *
  2170. * @param channel L2cap PSM/channel to connect to
  2171. * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
  2172. * @throws IOException on error, for example Bluetooth not available, or insufficient
  2173. * permissions
  2174. * @hide
  2175. */
  2176. @RequiresLegacyBluetoothPermission
  2177. @RequiresBluetoothConnectPermission
  2178. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  2179. @SuppressLint("AndroidFrameworkRequiresPermission")
  2180. public BluetoothSocket createInsecureL2capSocket(int channel) throws IOException {
  2181. return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, false, false, this, channel,
  2182. null);
  2183. }
  2184. /**
  2185. * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
  2186. * outgoing connection to this remote device using SDP lookup of uuid.
  2187. * <p>This is designed to be used with {@link
  2188. * BluetoothAdapter#listenUsingRfcommWithServiceRecord} for peer-peer
  2189. * Bluetooth applications.
  2190. * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
  2191. * connection. This will also perform an SDP lookup of the given uuid to
  2192. * determine which channel to connect to.
  2193. * <p>The remote device will be authenticated and communication on this
  2194. * socket will be encrypted.
  2195. * <p> Use this socket only if an authenticated socket link is possible.
  2196. * Authentication refers to the authentication of the link key to
  2197. * prevent person-in-the-middle type of attacks.
  2198. * For example, for Bluetooth 2.1 devices, if any of the devices does not
  2199. * have an input and output capability or just has the ability to
  2200. * display a numeric key, a secure socket connection is not possible.
  2201. * In such a case, use {@link #createInsecureRfcommSocketToServiceRecord}.
  2202. * For more details, refer to the Security Model section 5.2 (vol 3) of
  2203. * Bluetooth Core Specification version 2.1 + EDR.
  2204. * <p>Hint: If you are connecting to a Bluetooth serial board then try
  2205. * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
  2206. * However if you are connecting to an Android peer then please generate
  2207. * your own unique UUID.
  2208. *
  2209. * @param uuid service record uuid to lookup RFCOMM channel
  2210. * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
  2211. * @throws IOException on error, for example Bluetooth not available, or insufficient
  2212. * permissions
  2213. */
  2214. @RequiresLegacyBluetoothPermission
  2215. @RequiresBluetoothConnectPermission
  2216. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  2217. @SuppressLint("AndroidFrameworkRequiresPermission")
  2218. public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException {
  2219. if (!isBluetoothEnabled()) {
  2220. Log.e(TAG, "Bluetooth is not enabled");
  2221. throw new IOException();
  2222. }
  2223. return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, -1,
  2224. new ParcelUuid(uuid));
  2225. }
  2226. /**
  2227. * Create an RFCOMM {@link BluetoothSocket} socket ready to start an insecure
  2228. * outgoing connection to this remote device using SDP lookup of uuid.
  2229. * <p> The communication channel will not have an authenticated link key
  2230. * i.e it will be subject to person-in-the-middle attacks. For Bluetooth 2.1
  2231. * devices, the link key will be encrypted, as encryption is mandatory.
  2232. * For legacy devices (pre Bluetooth 2.1 devices) the link key will
  2233. * be not be encrypted. Use {@link #createRfcommSocketToServiceRecord} if an
  2234. * encrypted and authenticated communication channel is desired.
  2235. * <p>This is designed to be used with {@link
  2236. * BluetoothAdapter#listenUsingInsecureRfcommWithServiceRecord} for peer-peer
  2237. * Bluetooth applications.
  2238. * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
  2239. * connection. This will also perform an SDP lookup of the given uuid to
  2240. * determine which channel to connect to.
  2241. * <p>The remote device will be authenticated and communication on this
  2242. * socket will be encrypted.
  2243. * <p>Hint: If you are connecting to a Bluetooth serial board then try
  2244. * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
  2245. * However if you are connecting to an Android peer then please generate
  2246. * your own unique UUID.
  2247. *
  2248. * @param uuid service record uuid to lookup RFCOMM channel
  2249. * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
  2250. * @throws IOException on error, for example Bluetooth not available, or insufficient
  2251. * permissions
  2252. */
  2253. @RequiresLegacyBluetoothPermission
  2254. @RequiresBluetoothConnectPermission
  2255. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  2256. @SuppressLint("AndroidFrameworkRequiresPermission")
  2257. public BluetoothSocket createInsecureRfcommSocketToServiceRecord(UUID uuid) throws IOException {
  2258. if (!isBluetoothEnabled()) {
  2259. Log.e(TAG, "Bluetooth is not enabled");
  2260. throw new IOException();
  2261. }
  2262. return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, -1,
  2263. new ParcelUuid(uuid));
  2264. }
  2265. /**
  2266. * Construct an insecure RFCOMM socket ready to start an outgoing
  2267. * connection.
  2268. * Call #connect on the returned #BluetoothSocket to begin the connection.
  2269. * The remote device will not be authenticated and communication on this
  2270. * socket will not be encrypted.
  2271. *
  2272. * @param port remote port
  2273. * @return An RFCOMM BluetoothSocket
  2274. * @throws IOException On error, for example Bluetooth not available, or insufficient
  2275. * permissions.
  2276. * @hide
  2277. */
  2278. @UnsupportedAppUsage(publicAlternatives = "Use "
  2279. + "{@link #createInsecureRfcommSocketToServiceRecord} instead.")
  2280. @RequiresLegacyBluetoothAdminPermission
  2281. @RequiresBluetoothConnectPermission
  2282. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  2283. @SuppressLint("AndroidFrameworkRequiresPermission")
  2284. public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException {
  2285. if (!isBluetoothEnabled()) {
  2286. Log.e(TAG, "Bluetooth is not enabled");
  2287. throw new IOException();
  2288. }
  2289. return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, port,
  2290. null);
  2291. }
  2292. /**
  2293. * Construct a SCO socket ready to start an outgoing connection.
  2294. * Call #connect on the returned #BluetoothSocket to begin the connection.
  2295. *
  2296. * @return a SCO BluetoothSocket
  2297. * @throws IOException on error, for example Bluetooth not available, or insufficient
  2298. * permissions.
  2299. * @hide
  2300. */
  2301. @UnsupportedAppUsage
  2302. @RequiresLegacyBluetoothAdminPermission
  2303. @RequiresBluetoothConnectPermission
  2304. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  2305. @SuppressLint("AndroidFrameworkRequiresPermission")
  2306. public BluetoothSocket createScoSocket() throws IOException {
  2307. if (!isBluetoothEnabled()) {
  2308. Log.e(TAG, "Bluetooth is not enabled");
  2309. throw new IOException();
  2310. }
  2311. return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1, null);
  2312. }
  2313. /**
  2314. * Check that a pin is valid and convert to byte array.
  2315. *
  2316. * Bluetooth pin's are 1 to 16 bytes of UTF-8 characters.
  2317. *
  2318. * @param pin pin as java String
  2319. * @return the pin code as a UTF-8 byte array, or null if it is an invalid Bluetooth pin.
  2320. * @hide
  2321. */
  2322. @UnsupportedAppUsage
  2323. public static byte[] convertPinToBytes(String pin) {
  2324. if (pin == null) {
  2325. return null;
  2326. }
  2327. byte[] pinBytes;
  2328. try {
  2329. pinBytes = pin.getBytes("UTF-8");
  2330. } catch (UnsupportedEncodingException uee) {
  2331. Log.e(TAG, "UTF-8 not supported?!?"); // this should not happen
  2332. return null;
  2333. }
  2334. if (pinBytes.length <= 0 || pinBytes.length > 16) {
  2335. return null;
  2336. }
  2337. return pinBytes;
  2338. }
  2339. /**
  2340. * Connect to GATT Server hosted by this device. Caller acts as GATT client.
  2341. * The callback is used to deliver results to Caller, such as connection status as well
  2342. * as any further GATT client operations.
  2343. * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
  2344. * GATT client operations.
  2345. *
  2346. * @param callback GATT callback handler that will receive asynchronous callbacks.
  2347. * @param autoConnect Whether to directly connect to the remote device (false) or to
  2348. * automatically connect as soon as the remote device becomes available (true).
  2349. * @throws IllegalArgumentException if callback is null
  2350. */
  2351. @RequiresBluetoothConnectPermission
  2352. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  2353. public BluetoothGatt connectGatt(Context context, boolean autoConnect,
  2354. BluetoothGattCallback callback) {
  2355. return (connectGatt(context, autoConnect, callback, TRANSPORT_AUTO));
  2356. }
  2357. /**
  2358. * Connect to GATT Server hosted by this device. Caller acts as GATT client.
  2359. * The callback is used to deliver results to Caller, such as connection status as well
  2360. * as any further GATT client operations.
  2361. * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
  2362. * GATT client operations.
  2363. *
  2364. * @param callback GATT callback handler that will receive asynchronous callbacks.
  2365. * @param autoConnect Whether to directly connect to the remote device (false) or to
  2366. * automatically connect as soon as the remote device becomes available (true).
  2367. * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
  2368. * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
  2369. * BluetoothDevice#TRANSPORT_LE}
  2370. * @throws IllegalArgumentException if callback is null
  2371. */
  2372. @RequiresBluetoothConnectPermission
  2373. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  2374. public BluetoothGatt connectGatt(Context context, boolean autoConnect,
  2375. BluetoothGattCallback callback, int transport) {
  2376. return (connectGatt(context, autoConnect, callback, transport, PHY_LE_1M_MASK));
  2377. }
  2378. /**
  2379. * Connect to GATT Server hosted by this device. Caller acts as GATT client.
  2380. * The callback is used to deliver results to Caller, such as connection status as well
  2381. * as any further GATT client operations.
  2382. * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
  2383. * GATT client operations.
  2384. *
  2385. * @param callback GATT callback handler that will receive asynchronous callbacks.
  2386. * @param autoConnect Whether to directly connect to the remote device (false) or to
  2387. * automatically connect as soon as the remote device becomes available (true).
  2388. * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
  2389. * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
  2390. * BluetoothDevice#TRANSPORT_LE}
  2391. * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link
  2392. * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, and {@link
  2393. * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code autoConnect}
  2394. * is set to true.
  2395. * @throws NullPointerException if callback is null
  2396. */
  2397. @RequiresBluetoothConnectPermission
  2398. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  2399. public BluetoothGatt connectGatt(Context context, boolean autoConnect,
  2400. BluetoothGattCallback callback, int transport, int phy) {
  2401. return connectGatt(context, autoConnect, callback, transport, phy, null);
  2402. }
  2403. /**
  2404. * Connect to GATT Server hosted by this device. Caller acts as GATT client.
  2405. * The callback is used to deliver results to Caller, such as connection status as well
  2406. * as any further GATT client operations.
  2407. * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
  2408. * GATT client operations.
  2409. *
  2410. * @param callback GATT callback handler that will receive asynchronous callbacks.
  2411. * @param autoConnect Whether to directly connect to the remote device (false) or to
  2412. * automatically connect as soon as the remote device becomes available (true).
  2413. * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
  2414. * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
  2415. * BluetoothDevice#TRANSPORT_LE}
  2416. * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link
  2417. * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, an d{@link
  2418. * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code autoConnect}
  2419. * is set to true.
  2420. * @param handler The handler to use for the callback. If {@code null}, callbacks will happen on
  2421. * an un-specified background thread.
  2422. * @throws NullPointerException if callback is null
  2423. */
  2424. @RequiresBluetoothConnectPermission
  2425. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  2426. public BluetoothGatt connectGatt(Context context, boolean autoConnect,
  2427. BluetoothGattCallback callback, int transport, int phy,
  2428. Handler handler) {
  2429. return connectGatt(context, autoConnect, callback, transport, false, phy, handler);
  2430. }
  2431. /**
  2432. * Connect to GATT Server hosted by this device. Caller acts as GATT client.
  2433. * The callback is used to deliver results to Caller, such as connection status as well
  2434. * as any further GATT client operations.
  2435. * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
  2436. * GATT client operations.
  2437. *
  2438. * @param callback GATT callback handler that will receive asynchronous callbacks.
  2439. * @param autoConnect Whether to directly connect to the remote device (false) or to
  2440. * automatically connect as soon as the remote device becomes available (true).
  2441. * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
  2442. * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
  2443. * BluetoothDevice#TRANSPORT_LE}
  2444. * @param opportunistic Whether this GATT client is opportunistic. An opportunistic GATT client
  2445. * does not hold a GATT connection. It automatically disconnects when no other GATT connections
  2446. * are active for the remote device.
  2447. * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link
  2448. * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, an d{@link
  2449. * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code autoConnect}
  2450. * is set to true.
  2451. * @param handler The handler to use for the callback. If {@code null}, callbacks will happen on
  2452. * an un-specified background thread.
  2453. * @return A BluetoothGatt instance. You can use BluetoothGatt to conduct GATT client
  2454. * operations.
  2455. * @hide
  2456. */
  2457. @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
  2458. @RequiresBluetoothConnectPermission
  2459. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  2460. public BluetoothGatt connectGatt(Context context, boolean autoConnect,
  2461. BluetoothGattCallback callback, int transport,
  2462. boolean opportunistic, int phy, Handler handler) {
  2463. if (callback == null) {
  2464. throw new NullPointerException("callback is null");
  2465. }
  2466. // TODO(Bluetooth) check whether platform support BLE
  2467. // Do the check here or in GattServer?
  2468. BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
  2469. IBluetoothManager managerService = adapter.getBluetoothManager();
  2470. try {
  2471. IBluetoothGatt iGatt = managerService.getBluetoothGatt();
  2472. if (iGatt == null) {
  2473. // BLE is not supported
  2474. return null;
  2475. }
  2476. BluetoothGatt gatt = new BluetoothGatt(
  2477. iGatt, this, transport, opportunistic, phy, mAttributionSource);
  2478. gatt.connect(autoConnect, callback, handler);
  2479. return gatt;
  2480. } catch (RemoteException e) {
  2481. Log.e(TAG, "", e);
  2482. }
  2483. return null;
  2484. }
  2485. /**
  2486. * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can
  2487. * be used to start a secure outgoing connection to the remote device with the same dynamic
  2488. * protocol/service multiplexer (PSM) value. The supported Bluetooth transport is LE only.
  2489. * <p>This is designed to be used with {@link BluetoothAdapter#listenUsingL2capChannel()} for
  2490. * peer-peer Bluetooth applications.
  2491. * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection.
  2492. * <p>Application using this API is responsible for obtaining PSM value from remote device.
  2493. * <p>The remote device will be authenticated and communication on this socket will be
  2494. * encrypted.
  2495. * <p> Use this socket if an authenticated socket link is possible. Authentication refers
  2496. * to the authentication of the link key to prevent person-in-the-middle type of attacks.
  2497. *
  2498. * @param psm dynamic PSM value from remote device
  2499. * @return a CoC #BluetoothSocket ready for an outgoing connection
  2500. * @throws IOException on error, for example Bluetooth not available, or insufficient
  2501. * permissions
  2502. */
  2503. @RequiresLegacyBluetoothPermission
  2504. @RequiresBluetoothConnectPermission
  2505. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  2506. @SuppressLint("AndroidFrameworkRequiresPermission")
  2507. public @NonNull BluetoothSocket createL2capChannel(int psm) throws IOException {
  2508. if (!isBluetoothEnabled()) {
  2509. Log.e(TAG, "createL2capChannel: Bluetooth is not enabled");
  2510. throw new IOException();
  2511. }
  2512. if (DBG) Log.d(TAG, "createL2capChannel: psm=" + psm);
  2513. return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP_LE, -1, true, true, this, psm,
  2514. null);
  2515. }
  2516. /**
  2517. * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can
  2518. * be used to start a secure outgoing connection to the remote device with the same dynamic
  2519. * protocol/service multiplexer (PSM) value. The supported Bluetooth transport is LE only.
  2520. * <p>This is designed to be used with {@link
  2521. * BluetoothAdapter#listenUsingInsecureL2capChannel()} for peer-peer Bluetooth applications.
  2522. * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection.
  2523. * <p>Application using this API is responsible for obtaining PSM value from remote device.
  2524. * <p> The communication channel may not have an authenticated link key, i.e. it may be subject
  2525. * to person-in-the-middle attacks. Use {@link #createL2capChannel(int)} if an encrypted and
  2526. * authenticated communication channel is possible.
  2527. *
  2528. * @param psm dynamic PSM value from remote device
  2529. * @return a CoC #BluetoothSocket ready for an outgoing connection
  2530. * @throws IOException on error, for example Bluetooth not available, or insufficient
  2531. * permissions
  2532. */
  2533. @RequiresLegacyBluetoothPermission
  2534. @RequiresBluetoothConnectPermission
  2535. @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
  2536. @SuppressLint("AndroidFrameworkRequiresPermission")
  2537. public @NonNull BluetoothSocket createInsecureL2capChannel(int psm) throws IOException {
  2538. if (!isBluetoothEnabled()) {
  2539. Log.e(TAG, "createInsecureL2capChannel: Bluetooth is not enabled");
  2540. throw new IOException();
  2541. }
  2542. if (DBG) {
  2543. Log.d(TAG, "createInsecureL2capChannel: psm=" + psm);
  2544. }
  2545. return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP_LE, -1, false, false, this, psm,
  2546. null);
  2547. }
  2548. /**
  2549. * Set a keyed metadata of this {@link BluetoothDevice} to a
  2550. * {@link String} value.
  2551. * Only bonded devices's metadata will be persisted across Bluetooth
  2552. * restart.
  2553. * Metadata will be removed when the device's bond state is moved to
  2554. * {@link #BOND_NONE}.
  2555. *
  2556. * @param key must be within the list of BluetoothDevice.METADATA_*
  2557. * @param value a byte array data to set for key. Must be less than
  2558. * {@link BluetoothAdapter#METADATA_MAX_LENGTH} characters in length
  2559. * @return true on success, false on error
  2560. * @hide
  2561. */
  2562. @SystemApi
  2563. @RequiresPermission(allOf = {
  2564. android.Manifest.permission.BLUETOOTH_CONNECT,
  2565. android.Manifest.permission.BLUETOOTH_PRIVILEGED,
  2566. })
  2567. public boolean setMetadata(@MetadataKey int key, @NonNull byte[] value) {
  2568. final IBluetooth service = sService;
  2569. if (service == null) {
  2570. Log.e(TAG, "Bluetooth is not enabled. Cannot set metadata");
  2571. return false;
  2572. }
  2573. if (value.length > METADATA_MAX_LENGTH) {
  2574. throw new IllegalArgumentException("value length is " + value.length
  2575. + ", should not over " + METADATA_MAX_LENGTH);
  2576. }
  2577. try {
  2578. return service.setMetadata(this, key, value, mAttributionSource);
  2579. } catch (RemoteException e) {
  2580. Log.e(TAG, "setMetadata fail", e);
  2581. return false;
  2582. }
  2583. }
  2584. /**
  2585. * Get a keyed metadata for this {@link BluetoothDevice} as {@link String}
  2586. *
  2587. * @param key must be within the list of BluetoothDevice.METADATA_*
  2588. * @return Metadata of the key as byte array, null on error or not found
  2589. * @hide
  2590. */
  2591. @SystemApi
  2592. @Nullable
  2593. @RequiresPermission(allOf = {
  2594. android.Manifest.permission.BLUETOOTH_CONNECT,
  2595. android.Manifest.permission.BLUETOOTH_PRIVILEGED,
  2596. })
  2597. public byte[] getMetadata(@MetadataKey int key) {
  2598. final IBluetooth service = sService;
  2599. if (service == null) {
  2600. Log.e(TAG, "Bluetooth is not enabled. Cannot get metadata");
  2601. return null;
  2602. }
  2603. try {
  2604. return service.getMetadata(this, key, mAttributionSource);
  2605. } catch (RemoteException e) {
  2606. Log.e(TAG, "getMetadata fail", e);
  2607. return null;
  2608. }
  2609. }
  2610. /**
  2611. * Get the maxinum metadata key ID.
  2612. *
  2613. * @return the last supported metadata key
  2614. * @hide
  2615. */
  2616. public static @MetadataKey int getMaxMetadataKey() {
  2617. return METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD;
  2618. }
  2619. }