diff options
author | Ćukasz Rymanowski <rlukasz@google.com> | 2022-01-19 20:04:59 +0000 |
---|---|---|
committer | Jack He <siyuanh@google.com> | 2022-02-02 15:17:34 -0800 |
commit | b99f7eced58e8e722366ce364a8a2eef4e4449e0 (patch) | |
tree | 7920d644262d8b1c1f48f85070bb3a0ad48ff70b /framework/java/android/bluetooth/BluetoothVolumeControl.java | |
parent | 599bf26cd0f785ce41185d43df5debc25533a7d9 (diff) |
leaudio: Improve Volume Control API
On the Le Audio device absolute volume is set via
BluetoothLeAudio.setVolume API. LeAudioService knows which group is the
active group and using BluetoothVolumeControl.setVolumeGroup() API apply
absolute volume.
Each LeAudio device is a part of the group.
In order to support audio balance between e.g. left and right earbud
setVolumeOffset should be use per each device.
This change also allows user to register for the callback which will
be invoked when the volume offset changes on the remote device.
Bug: 150670922
Tag: #feature
Sponsor: @jpawlowski
Test: atest BluetoothInstrumentationTests
Change-Id: I3692e45d285d55d946ae0de187aa1d5261f825b8
Merged-In: I3692e45d285d55d946ae0de187aa1d5261f825b8
(cherry picked from commit 470384a052a972bebe52483de0099d9d0f47b343)
Diffstat (limited to 'framework/java/android/bluetooth/BluetoothVolumeControl.java')
-rw-r--r-- | framework/java/android/bluetooth/BluetoothVolumeControl.java | 123 |
1 files changed, 116 insertions, 7 deletions
diff --git a/framework/java/android/bluetooth/BluetoothVolumeControl.java b/framework/java/android/bluetooth/BluetoothVolumeControl.java index 27532aabc3..fb8abb1cf2 100644 --- a/framework/java/android/bluetooth/BluetoothVolumeControl.java +++ b/framework/java/android/bluetooth/BluetoothVolumeControl.java @@ -20,6 +20,7 @@ package android.bluetooth; import static android.bluetooth.BluetoothUtils.getSyncTimeout; import android.Manifest; +import android.annotation.CallbackExecutor; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; @@ -40,6 +41,7 @@ import com.android.modules.utils.SynchronousResultReceiver; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Executor; import java.util.concurrent.TimeoutException; /** @@ -59,6 +61,33 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose private CloseGuard mCloseGuard; /** + * This class provides a callback that is invoked when volume offset value changes on + * the remote device. + * + * <p> In order to balance volume on the group of Le Audio devices, + * Volume Offset Control Service (VOCS) shall be used. User can verify + * if the remote device supports VOCS by calling {@link #isVolumeOffsetAvailable(device)}. + * + * @hide + */ + @SystemApi + public interface Callback { + /** + * Callback invoked when callback is registered and when volume offset + * changes on the remote device. Change can be triggered autonomously by the remote device + * or after volume offset change on the user request done by calling + * {@link #setVolumeOffset(device, volumeOffset)} + * + * @param device remote device whose volume offset changed + * @param volumeOffset latest volume offset for this device + * @hide + */ + @SystemApi + void onVolumeOffsetChanged(@NonNull BluetoothDevice device, + @IntRange(from = -255, to = 255) int volumeOffset); + } + + /** * Intent used to broadcast the change in connection state of the Volume Control * profile. * @@ -217,10 +246,68 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose } /** - * Tells remote device to set an absolute volume. + * Register a {@link Callback} that will be invoked during the + * operation of this profile. + * + * Repeated registration of the same <var>callback</var> object will have no effect after + * the first call to this method, even when the <var>executor</var> is different. API caller + * would have to call {@link #unregisterCallback(Callback)} with + * the same callback object before registering it again. + * + * @param executor an {@link Executor} to execute given callback + * @param callback user implementation of the {@link Callback} + * @throws IllegalArgumentException if a null executor, sink, or callback is given + * @hide + */ + @SystemApi + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public void registerCallback(@NonNull @CallbackExecutor Executor executor, + @NonNull Callback callback) { + if (executor == null) { + throw new IllegalArgumentException("executor cannot be null"); + } + if (callback == null) { + throw new IllegalArgumentException("callback cannot be null"); + } + if (DBG) log("registerCallback"); + throw new UnsupportedOperationException("Not Implemented"); + } + + /** + * Unregister the specified {@link Callback}. + * <p>The same {@link Callback} object used when calling + * {@link #registerCallback(Executor, Callback)} must be used. + * + * <p>Callbacks are automatically unregistered when application process goes away + * + * @param callback user implementation of the {@link Callback} + * @throws IllegalArgumentException when callback is null or when no callback is registered + * @hide + */ + @SystemApi + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public void unregisterCallback(@NonNull Callback callback) { + if (callback == null) { + throw new IllegalArgumentException("callback cannot be null"); + } + if (DBG) log("unregisterCallback"); + throw new UnsupportedOperationException("Not Implemented"); + } + + /** + * Tells the remote device to set a volume offset to the absolute volume. + * + * @param device {@link BluetoothDevice} representing the remote device + * @param volumeOffset volume offset to be set on the remote device * - * @param volume Absolute volume to be set on remote device. - * Minimum value is 0 and maximum value is 255 * @hide */ @SystemApi @@ -229,9 +316,9 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED, }) - public void setVolume(@Nullable BluetoothDevice device, - @IntRange(from = 0, to = 255) int volume) { - if (DBG) log("setVolume(" + volume + ")"); + public void setVolumeOffset(@NonNull BluetoothDevice device, + @IntRange(from = -255, to = 255) int volumeOffset) { + if (DBG) log("setVolumeOffset(" + device + " volumeOffset: " + volumeOffset + ")"); final IBluetoothVolumeControl service = getService(); if (service == null) { Log.w(TAG, "Proxy not attached to service"); @@ -239,7 +326,7 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose } else if (isEnabled()) { try { final SynchronousResultReceiver recv = new SynchronousResultReceiver(); - service.setVolume(device, volume, mAttributionSource, recv); + service.setVolumeOffset(device, volumeOffset, mAttributionSource, recv); recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null); } catch (RemoteException | TimeoutException e) { Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable())); @@ -248,6 +335,28 @@ public final class BluetoothVolumeControl implements BluetoothProfile, AutoClose } /** + * Provides information about the possibility to set volume offset on the remote device. + * If the remote device supports Volume Offset Control Service, it is automatically + * connected. + * + * @param device {@link BluetoothDevice} representing the remote device + * @return {@code true} if volume offset function is supported and available to use on the + * remote device. When Bluetooth is off, the return value should always be + * {@code false}. + * @hide + */ + @SystemApi + @RequiresBluetoothConnectPermission + @RequiresPermission(allOf = { + android.Manifest.permission.BLUETOOTH_CONNECT, + android.Manifest.permission.BLUETOOTH_PRIVILEGED, + }) + public boolean isVolumeOffsetAvailable(@NonNull BluetoothDevice device) { + if (DBG) log("isVolumeOffsetAvailable(" + device + ")"); + return false; + } + + /** * Set connection policy of the profile * * <p> The device should already be paired. |