Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 64d4e6b6 authored by Etienne Ruffieux's avatar Etienne Ruffieux
Browse files

Made Bluetooth codec configuration APIs public.

Continuation of the work started in Android T of making
Bluetooth codec configuration available via public APIs.

BluetoothA2dp#setCodecConfigPreference, BluetoothA2dp#
getCodecStatus & BluetoothA2dp#ACTION_CODEC_CONFIG_CHANGED
are made public instead of system APIs.
setCodecConfigPreference requires a CDM association between
the calling application and the Bluetooth device.

Bug: 170678351
Tag: #feature
Test: atest FrameworkBluetoothTests
Change-Id: I40597060127cf2499548d1906d3d5743f157e131
parent ea88e351
Loading
Loading
Loading
Loading
+10 −0
Original line number Original line Diff line number Diff line
@@ -20,6 +20,8 @@ import static android.Manifest.permission.BLUETOOTH_CONNECT;


import static com.android.bluetooth.Utils.checkCallerTargetSdk;
import static com.android.bluetooth.Utils.checkCallerTargetSdk;
import static com.android.bluetooth.Utils.enforceBluetoothPrivilegedPermission;
import static com.android.bluetooth.Utils.enforceBluetoothPrivilegedPermission;
import static com.android.bluetooth.Utils.enforceCdmAssociation;
import static com.android.bluetooth.Utils.hasBluetoothPrivilegedPermission;


import android.annotation.RequiresPermission;
import android.annotation.RequiresPermission;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothA2dp;
@@ -32,6 +34,7 @@ import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.bluetooth.BluetoothUuid;
import android.bluetooth.BufferConstraints;
import android.bluetooth.BufferConstraints;
import android.bluetooth.IBluetoothA2dp;
import android.bluetooth.IBluetoothA2dp;
import android.companion.CompanionDeviceManager;
import android.content.AttributionSource;
import android.content.AttributionSource;
import android.content.BroadcastReceiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Context;
@@ -39,6 +42,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.media.AudioManager;
import android.media.BluetoothProfileConnectionInfo;
import android.media.BluetoothProfileConnectionInfo;
import android.os.Binder;
import android.os.Build;
import android.os.Build;
import android.os.HandlerThread;
import android.os.HandlerThread;
import android.sysprop.BluetoothProperties;
import android.sysprop.BluetoothProperties;
@@ -83,6 +87,7 @@ public class A2dpService extends ProfileService {
    ServiceFactory mFactory = new ServiceFactory();
    ServiceFactory mFactory = new ServiceFactory();
    private AudioManager mAudioManager;
    private AudioManager mAudioManager;
    private A2dpCodecConfig mA2dpCodecConfig;
    private A2dpCodecConfig mA2dpCodecConfig;
    private CompanionDeviceManager mCompanionDeviceManager;


    @GuardedBy("mStateMachines")
    @GuardedBy("mStateMachines")
    private BluetoothDevice mActiveDevice;
    private BluetoothDevice mActiveDevice;
@@ -135,6 +140,7 @@ public class A2dpService extends ProfileService {
        mDatabaseManager = Objects.requireNonNull(mAdapterService.getDatabase(),
        mDatabaseManager = Objects.requireNonNull(mAdapterService.getDatabase(),
                "DatabaseManager cannot be null when A2dpService starts");
                "DatabaseManager cannot be null when A2dpService starts");
        mAudioManager = getSystemService(AudioManager.class);
        mAudioManager = getSystemService(AudioManager.class);
        mCompanionDeviceManager = getSystemService(CompanionDeviceManager.class);
        Objects.requireNonNull(mAudioManager,
        Objects.requireNonNull(mAudioManager,
                               "AudioManager cannot be null when A2dpService starts");
                               "AudioManager cannot be null when A2dpService starts");


@@ -1480,6 +1486,10 @@ public class A2dpService extends ProfileService {
            if (service == null) {
            if (service == null) {
                return;
                return;
            }
            }
            if (!hasBluetoothPrivilegedPermission(service)) {
                enforceCdmAssociation(service.mCompanionDeviceManager, service,
                        source.getPackageName(), Binder.getCallingUid(), device);
            }
            service.setCodecConfigPreference(device, codecConfig);
            service.setCodecConfigPreference(device, codecConfig);
        }
        }


+7 −0
Original line number Original line Diff line number Diff line
@@ -3,10 +3,13 @@ package android.bluetooth {


  public final class BluetoothA2dp implements android.bluetooth.BluetoothProfile {
  public final class BluetoothA2dp implements android.bluetooth.BluetoothProfile {
    method public void finalize();
    method public void finalize();
    method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public android.bluetooth.BluetoothCodecStatus getCodecStatus(@NonNull android.bluetooth.BluetoothDevice);
    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(android.bluetooth.BluetoothDevice);
    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public int getConnectionState(android.bluetooth.BluetoothDevice);
    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isA2dpPlaying(android.bluetooth.BluetoothDevice);
    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean isA2dpPlaying(android.bluetooth.BluetoothDevice);
    method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public void setCodecConfigPreference(@NonNull android.bluetooth.BluetoothDevice, @NonNull android.bluetooth.BluetoothCodecConfig);
    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CODEC_CONFIG_CHANGED = "android.bluetooth.a2dp.profile.action.CODEC_CONFIG_CHANGED";
    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED";
    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED";
    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_PLAYING_STATE_CHANGED = "android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED";
    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_PLAYING_STATE_CHANGED = "android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED";
    field public static final int STATE_NOT_PLAYING = 11; // 0xb
    field public static final int STATE_NOT_PLAYING = 11; // 0xb
@@ -443,6 +446,10 @@ package android.bluetooth {
    field public static final int CODEC_PRIORITY_DEFAULT = 0; // 0x0
    field public static final int CODEC_PRIORITY_DEFAULT = 0; // 0x0
    field public static final int CODEC_PRIORITY_DISABLED = -1; // 0xffffffff
    field public static final int CODEC_PRIORITY_DISABLED = -1; // 0xffffffff
    field public static final int CODEC_PRIORITY_HIGHEST = 1000000; // 0xf4240
    field public static final int CODEC_PRIORITY_HIGHEST = 1000000; // 0xf4240
    field public static final int CODEC_SPECIFIC_1_LDAC_QUALITY_ADAPTIVE = 1003; // 0x3eb
    field public static final int CODEC_SPECIFIC_1_LDAC_QUALITY_HIGH = 1000; // 0x3e8
    field public static final int CODEC_SPECIFIC_1_LDAC_QUALITY_LOW = 1002; // 0x3ea
    field public static final int CODEC_SPECIFIC_1_LDAC_QUALITY_MID = 1001; // 0x3e9
    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothCodecConfig> CREATOR;
    field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothCodecConfig> CREATOR;
    field public static final int SAMPLE_RATE_176400 = 16; // 0x10
    field public static final int SAMPLE_RATE_176400 = 16; // 0x10
    field public static final int SAMPLE_RATE_192000 = 32; // 0x20
    field public static final int SAMPLE_RATE_192000 = 32; // 0x20
+0 −3
Original line number Original line Diff line number Diff line
@@ -5,18 +5,15 @@ package android.bluetooth {
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void disableOptionalCodecs(@NonNull android.bluetooth.BluetoothDevice);
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void disableOptionalCodecs(@NonNull android.bluetooth.BluetoothDevice);
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void enableOptionalCodecs(@NonNull android.bluetooth.BluetoothDevice);
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void enableOptionalCodecs(@NonNull android.bluetooth.BluetoothDevice);
    method @Nullable @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public android.bluetooth.BufferConstraints getBufferConstraints();
    method @Nullable @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public android.bluetooth.BufferConstraints getBufferConstraints();
    method @Nullable @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public android.bluetooth.BluetoothCodecStatus getCodecStatus(@NonNull android.bluetooth.BluetoothDevice);
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getDynamicBufferSupport();
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int getDynamicBufferSupport();
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int isOptionalCodecsEnabled(@NonNull android.bluetooth.BluetoothDevice);
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int isOptionalCodecsEnabled(@NonNull android.bluetooth.BluetoothDevice);
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int isOptionalCodecsSupported(@NonNull android.bluetooth.BluetoothDevice);
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public int isOptionalCodecsSupported(@NonNull android.bluetooth.BluetoothDevice);
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void setAvrcpAbsoluteVolume(int);
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void setAvrcpAbsoluteVolume(int);
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setBufferLengthMillis(int, int);
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setBufferLengthMillis(int, int);
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void setCodecConfigPreference(@NonNull android.bluetooth.BluetoothDevice, @NonNull android.bluetooth.BluetoothCodecConfig);
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void setOptionalCodecsEnabled(@NonNull android.bluetooth.BluetoothDevice, int);
    method @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED}) public void setOptionalCodecsEnabled(@NonNull android.bluetooth.BluetoothDevice, int);
    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_ACTIVE_DEVICE_CHANGED = "android.bluetooth.a2dp.profile.action.ACTIVE_DEVICE_CHANGED";
    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_ACTIVE_DEVICE_CHANGED = "android.bluetooth.a2dp.profile.action.ACTIVE_DEVICE_CHANGED";
    field @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public static final String ACTION_CODEC_CONFIG_CHANGED = "android.bluetooth.a2dp.profile.action.CODEC_CONFIG_CHANGED";
    field public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD = 1; // 0x1
    field public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD = 1; // 0x1
    field public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING = 2; // 0x2
    field public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING = 2; // 0x2
    field public static final int DYNAMIC_BUFFER_SUPPORT_NONE = 0; // 0x0
    field public static final int DYNAMIC_BUFFER_SUPPORT_NONE = 0; // 0x0
+18 −21
Original line number Original line Diff line number Diff line
@@ -144,10 +144,7 @@ public final class BluetoothA2dp implements BluetoothProfile {
     * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device if the device is currently
     * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device if the device is currently
     * connected, otherwise it is not included.</li>
     * connected, otherwise it is not included.</li>
     * </ul>
     * </ul>
     *
     * @hide
     */
     */
    @SystemApi
    @RequiresLegacyBluetoothPermission
    @RequiresLegacyBluetoothPermission
    @RequiresBluetoothConnectPermission
    @RequiresBluetoothConnectPermission
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
@@ -770,20 +767,15 @@ public final class BluetoothA2dp implements BluetoothProfile {
    }
    }


    /**
    /**
     * Gets the current codec status (configuration and capability).
     * Retrieves the current codec configuration and the capabilities of the remote {@code device}.
     *
     *
     * @param device the remote Bluetooth device.
     * @param device the remote Bluetooth device
     * @return the current codec status
     * @return       the current codec status of the remote Bluetooth device
     * @hide
     */
     */
    @SystemApi
    @Nullable
    @Nullable
    @RequiresLegacyBluetoothPermission
    @RequiresLegacyBluetoothPermission
    @RequiresBluetoothConnectPermission
    @RequiresBluetoothConnectPermission
    @RequiresPermission(allOf = {
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
            android.Manifest.permission.BLUETOOTH_CONNECT,
            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
    })
    public BluetoothCodecStatus getCodecStatus(@NonNull BluetoothDevice device) {
    public BluetoothCodecStatus getCodecStatus(@NonNull BluetoothDevice device) {
        if (DBG) Log.d(TAG, "getCodecStatus(" + device + ")");
        if (DBG) Log.d(TAG, "getCodecStatus(" + device + ")");
        verifyDeviceNotNull(device, "getCodecStatus");
        verifyDeviceNotNull(device, "getCodecStatus");
@@ -806,19 +798,24 @@ public final class BluetoothA2dp implements BluetoothProfile {
    }
    }


    /**
    /**
     * Sets the codec configuration preference.
     * Sets the preferred codec configuration of remote {@code device}.
     *
     *
     * @param device the remote Bluetooth device.
     * The configuration must contain only selectable parameters in order to be used.
     * @param codecConfig the codec configuration preference
     * See {@link #getCodecStatus} and {@link BluetoothCodecStatus#isCodecConfigSelectable}.
     * @hide
     *
     * <p>This method requires the calling app to be associated with Companion Device Manager (see
     * {@link android.companion.CompanionDeviceManager#associate(AssociationRequest,
     * android.companion.CompanionDeviceManager.Callback, Handler)}) and have the
     * {@link android.Manifest.permission#BLUETOOTH_CONNECT} permission. Alternatively, if the
     * caller has the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission, they can
     * bypass the Companion Device Manager association requirement.
     *
     * @param device      the remote Bluetooth device
     * @param codecConfig the preferred codec configuration preference
     */
     */
    @SystemApi
    @RequiresLegacyBluetoothPermission
    @RequiresLegacyBluetoothPermission
    @RequiresBluetoothConnectPermission
    @RequiresBluetoothConnectPermission
    @RequiresPermission(allOf = {
    @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
            android.Manifest.permission.BLUETOOTH_CONNECT,
            android.Manifest.permission.BLUETOOTH_PRIVILEGED,
    })
    public void setCodecConfigPreference(@NonNull BluetoothDevice device,
    public void setCodecConfigPreference(@NonNull BluetoothDevice device,
                                         @NonNull BluetoothCodecConfig codecConfig) {
                                         @NonNull BluetoothCodecConfig codecConfig) {
        if (DBG) Log.d(TAG, "setCodecConfigPreference(" + device + ")");
        if (DBG) Log.d(TAG, "setCodecConfigPreference(" + device + ")");
+30 −1
Original line number Original line Diff line number Diff line
@@ -219,6 +219,36 @@ public final class BluetoothCodecConfig implements Parcelable {
     */
     */
    public static final int CHANNEL_MODE_STEREO = 0x1 << 1;
    public static final int CHANNEL_MODE_STEREO = 0x1 << 1;


    /** @hide */
    @IntDef(prefix = "CODEC_SPECIFIC_1_LDAC_", value = {
            CODEC_SPECIFIC_1_LDAC_QUALITY_HIGH,
            CODEC_SPECIFIC_1_LDAC_QUALITY_MID,
            CODEC_SPECIFIC_1_LDAC_QUALITY_LOW,
            CODEC_SPECIFIC_1_LDAC_QUALITY_ADAPTIVE
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface CodecSpecific1Ldac {}

    /**
     * Codec specific value for LDAC high quality bitrate.
     */
    public static final int CODEC_SPECIFIC_1_LDAC_QUALITY_HIGH = 1000;

    /**
     * Codec specific value for LDAC medium quality bitrate.
     */
    public static final int CODEC_SPECIFIC_1_LDAC_QUALITY_MID = 1001;

    /**
     * Codec specific value for LDAC low quality bitrate.
     */
    public static final int CODEC_SPECIFIC_1_LDAC_QUALITY_LOW = 1002;

    /**
     * Codec specific value for LDAC adaptive bitrate.
     */
    public static final int CODEC_SPECIFIC_1_LDAC_QUALITY_ADAPTIVE = 1003;

    private final @SourceCodecType int mCodecType;
    private final @SourceCodecType int mCodecType;
    private @CodecPriority int mCodecPriority;
    private @CodecPriority int mCodecPriority;
    private final @SampleRate int mSampleRate;
    private final @SampleRate int mSampleRate;
@@ -241,7 +271,6 @@ public final class BluetoothCodecConfig implements Parcelable {
     * @param codecSpecific2 the specific value 2
     * @param codecSpecific2 the specific value 2
     * @param codecSpecific3 the specific value 3
     * @param codecSpecific3 the specific value 3
     * @param codecSpecific4 the specific value 4
     * @param codecSpecific4 the specific value 4
     * values to 0.
     * @hide
     * @hide
     */
     */
    @UnsupportedAppUsage
    @UnsupportedAppUsage