diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 35be1c75d86f9..ff4e68736c687 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -1982,8 +1982,10 @@ package android.bluetooth { public final class BluetoothDevice implements android.os.Parcelable { method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean canBondWithoutDialog(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean cancelBondProcess(); + method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, android.Manifest.permission.MODIFY_PHONE_STATE}) public int connect(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean createBond(int); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean createBondOutOfBand(int, @Nullable android.bluetooth.OobData, @Nullable android.bluetooth.OobData); + method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int disconnect(); method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean fetchUuidsWithSdp(int); method @Nullable @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public byte[] getMetadata(int); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getSimAccessPermission(); diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 0783fccbaed80..06979ecdd4f66 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -2004,71 +2004,6 @@ public final class BluetoothAdapter { return false; } - /** - * Connects all enabled and supported bluetooth profiles between the local and remote device. - * Connection is asynchronous and you should listen to each profile's broadcast intent - * ACTION_CONNECTION_STATE_CHANGED to verify whether connection was successful. For example, - * to verify a2dp is connected, you would listen for - * {@link BluetoothA2dp#ACTION_CONNECTION_STATE_CHANGED} - * - * @param device is the remote device with which to connect these profiles - * @return true if message sent to try to connect all profiles, false if an error occurred - * - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - android.Manifest.permission.MODIFY_PHONE_STATE, - }) - public boolean connectAllEnabledProfiles(@NonNull BluetoothDevice device) { - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.connectAllEnabledProfiles(device, mAttributionSource); - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - - return false; - } - - /** - * Disconnects all enabled and supported bluetooth profiles between the local and remote device. - * Disconnection is asynchronous and you should listen to each profile's broadcast intent - * ACTION_CONNECTION_STATE_CHANGED to verify whether disconnection was successful. For example, - * to verify a2dp is disconnected, you would listen for - * {@link BluetoothA2dp#ACTION_CONNECTION_STATE_CHANGED} - * - * @param device is the remote device with which to disconnect these profiles - * @return true if message sent to try to disconnect all profiles, false if an error occurred - * - * @hide - */ - @RequiresBluetoothConnectPermission - @RequiresPermission(allOf = { - android.Manifest.permission.BLUETOOTH_CONNECT, - android.Manifest.permission.BLUETOOTH_PRIVILEGED, - }) - public boolean disconnectAllEnabledProfiles(@NonNull BluetoothDevice device) { - try { - mServiceLock.readLock().lock(); - if (mService != null) { - return mService.disconnectAllEnabledProfiles(device, mAttributionSource); - } - } catch (RemoteException e) { - Log.e(TAG, "", e); - } finally { - mServiceLock.readLock().unlock(); - } - - return false; - } - /** * Return true if the multi advertisement is supported by the chipset * diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index 71f05f5221ef8..6e918bd6243d6 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -1683,6 +1683,90 @@ public final class BluetoothDevice implements Parcelable, Attributable { return false; } + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + BluetoothStatusCodes.SUCCESS, + BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED, + BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED, + BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION, + BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED + }) + public @interface ConnectionReturnValues{} + + /** + * Connects all user enabled and supported bluetooth profiles between the local and remote + * device. If no profiles are user enabled (e.g. first connection), we connect all supported + * profiles. If the device is not already connected, this will page the device before initiating + * profile connections. Connection is asynchronous and you should listen to each profile's + * broadcast intent ACTION_CONNECTION_STATE_CHANGED to verify whether connection was successful. + * For example, to verify a2dp is connected, you would listen for + * {@link BluetoothA2dp#ACTION_CONNECTION_STATE_CHANGED} + * + * @return whether the messages were successfully sent to try to connect all profiles + * @throws IllegalArgumentException if the device address is invalid + * + * @hide + */ + @SystemApi + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + android.Manifest.permission.MODIFY_PHONE_STATE, + }) + public @ConnectionReturnValues int connect() { + if (!BluetoothAdapter.checkBluetoothAddress(getAddress())) { + throw new IllegalArgumentException("device cannot have an invalid address"); + } + + try { + if (sService == null) { + Log.e(TAG, "BT not enabled. Cannot connect to remote device."); + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; + } + return sService.connectAllEnabledProfiles(this, mAttributionSource); + } catch (RemoteException e) { + Log.e(TAG, "", e); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Disconnects all connected bluetooth profiles between the local and remote device. + * Disconnection is asynchronous and you should listen to each profile's broadcast intent + * ACTION_CONNECTION_STATE_CHANGED to verify whether disconnection was successful. For example, + * to verify a2dp is disconnected, you would listen for + * {@link BluetoothA2dp#ACTION_CONNECTION_STATE_CHANGED} + * + * @return whether the messages were successfully sent to try to disconnect all profiles + * @throws IllegalArgumentException if the device address is invalid + * + * @hide + */ + @SystemApi + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public @ConnectionReturnValues int disconnect() { + if (!BluetoothAdapter.checkBluetoothAddress(getAddress())) { + throw new IllegalArgumentException("device cannot have an invalid address"); + } + + try { + if (sService == null) { + Log.e(TAG, "BT not enabled. Cannot disconnect from remote device."); + return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED; + } + return sService.disconnectAllEnabledProfiles(this, mAttributionSource); + } catch (RemoteException e) { + Log.e(TAG, "", e); + throw e.rethrowFromSystemServer(); + } + } + /** * Returns whether there is an open connection to this device. * diff --git a/core/java/android/bluetooth/BluetoothStatusCodes.java b/core/java/android/bluetooth/BluetoothStatusCodes.java index 31bb0f68c6fcc..3e46c498e336e 100644 --- a/core/java/android/bluetooth/BluetoothStatusCodes.java +++ b/core/java/android/bluetooth/BluetoothStatusCodes.java @@ -21,7 +21,7 @@ import android.annotation.SystemApi; /** * A class with constants representing possible return values for Bluetooth APIs. General return * values occupy the range 0 to 99. Profile-specific return values occupy the range 100-999. - * API-specific return values start at 1000. The exception to this is the "other" error code which + * API-specific return values start at 1000. The exception to this is the "UNKNOWN" error code which * occupies the max integer value. */ public final class BluetoothStatusCodes { diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index 5ecff44c4d137..7ce9b516990e2 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -273,7 +273,7 @@ public class CachedBluetoothDevice implements Comparable public void disconnect() { synchronized (mProfileLock) { - mLocalAdapter.disconnectAllEnabledProfiles(mDevice); + mDevice.disconnect(); } // Disconnect PBAP server in case its connected // This is to ensure all the profiles are disconnected as some CK/Hs do not @@ -314,7 +314,7 @@ public class CachedBluetoothDevice implements Comparable } mConnectAttempted = SystemClock.elapsedRealtime(); - connectAllEnabledProfiles(); + connectDevice(); } public long getHiSyncId() { @@ -371,7 +371,7 @@ public class CachedBluetoothDevice implements Comparable connect(); } - private void connectAllEnabledProfiles() { + private void connectDevice() { synchronized (mProfileLock) { // Try to initialize the profiles if they were not. if (mProfiles.isEmpty()) { @@ -386,7 +386,7 @@ public class CachedBluetoothDevice implements Comparable return; } - mLocalAdapter.connectAllEnabledProfiles(mDevice); + mDevice.connect(); } } @@ -769,8 +769,8 @@ public class CachedBluetoothDevice implements Comparable * Otherwise, allow the connect on UUID change. */ if ((mConnectAttempted + timeout) > SystemClock.elapsedRealtime()) { - Log.d(TAG, "onUuidChanged: triggering connectAllEnabledProfiles"); - connectAllEnabledProfiles(); + Log.d(TAG, "onUuidChanged: triggering connectDevice"); + connectDevice(); } dispatchAttributesChanged();