Add adjust-only absolute volume behavior.
Adjust-only behavior (DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY)
is a variant of absolute behavior (DEVICE_VOLUME_BEHAVIOR_ABSOLUTE).
Like ABSOLUTE, ADJUST_ONLY may be adopted by calling a hidden API in
AudioDeviceVolumeManager and providing a listener for volume changes.
The difference with ADJUST_ONLY behavior is that setting volume via
AudioManager#setStreamVolume does not necessarily have an effect.
However, the listener is still notified of setStreamVolume calls
in case there's a slow or less reliable method of setting volume.
ADJUST_ONLY behavior may be returned by getDeviceVolumeBehavior for
SDK level U or higher. For lower SDK levels, FULL volume behavior is
returned in its place, as it is a similar but less powerful behavior.
Bug: 240663182
Test: atest AbsoluteVolumeBehaviorTest
Change-Id: I389bdd650dee717c4b249c989f4a9ee21c4eded7
diff --git a/media/java/android/media/AudioDeviceVolumeManager.java b/media/java/android/media/AudioDeviceVolumeManager.java
index 77fa9dc..bf3612d 100644
--- a/media/java/android/media/AudioDeviceVolumeManager.java
+++ b/media/java/android/media/AudioDeviceVolumeManager.java
@@ -146,13 +146,16 @@
* @param register true for registering, false for unregistering
* @param device device for which volume is monitored
*/
+ @RequiresPermission(anyOf = { android.Manifest.permission.MODIFY_AUDIO_ROUTING,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED })
public void register(boolean register, @NonNull AudioDeviceAttributes device,
- @NonNull List<VolumeInfo> volumes, boolean handlesVolumeAdjustment) {
+ @NonNull List<VolumeInfo> volumes, boolean handlesVolumeAdjustment,
+ @AudioManager.AbsoluteDeviceVolumeBehavior int behavior) {
try {
getService().registerDeviceVolumeDispatcherForAbsoluteVolume(register,
this, mPackageName,
Objects.requireNonNull(device), Objects.requireNonNull(volumes),
- handlesVolumeAdjustment);
+ handlesVolumeAdjustment, behavior);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
@@ -234,6 +237,77 @@
@NonNull @CallbackExecutor Executor executor,
@NonNull OnAudioDeviceVolumeChangedListener vclistener,
boolean handlesVolumeAdjustment) {
+ baseSetDeviceAbsoluteMultiVolumeBehavior(device, volumes, executor, vclistener,
+ handlesVolumeAdjustment, AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
+ }
+
+ /**
+ * @hide
+ * Configures a device to use absolute volume model, and registers a listener for receiving
+ * volume updates to apply on that device.
+ *
+ * Should be used instead of {@link #setDeviceAbsoluteVolumeBehavior} when there is no reliable
+ * way to set the device's volume to a percentage.
+ *
+ * @param device the audio device set to absolute volume mode
+ * @param volume the type of volume this device responds to
+ * @param executor the Executor used for receiving volume updates through the listener
+ * @param vclistener the callback for volume updates
+ */
+ @RequiresPermission(anyOf = { android.Manifest.permission.MODIFY_AUDIO_ROUTING,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED })
+ public void setDeviceAbsoluteVolumeAdjustOnlyBehavior(
+ @NonNull AudioDeviceAttributes device,
+ @NonNull VolumeInfo volume,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OnAudioDeviceVolumeChangedListener vclistener,
+ boolean handlesVolumeAdjustment) {
+ final ArrayList<VolumeInfo> volumes = new ArrayList<>(1);
+ volumes.add(volume);
+ setDeviceAbsoluteMultiVolumeAdjustOnlyBehavior(device, volumes, executor, vclistener,
+ handlesVolumeAdjustment);
+ }
+
+ /**
+ * @hide
+ * Configures a device to use absolute volume model applied to different volume types, and
+ * registers a listener for receiving volume updates to apply on that device.
+ *
+ * Should be used instead of {@link #setDeviceAbsoluteMultiVolumeBehavior} when there is
+ * no reliable way to set the device's volume to a percentage.
+ *
+ * @param device the audio device set to absolute multi-volume mode
+ * @param volumes the list of volumes the given device responds to
+ * @param executor the Executor used for receiving volume updates through the listener
+ * @param vclistener the callback for volume updates
+ */
+ @RequiresPermission(anyOf = { android.Manifest.permission.MODIFY_AUDIO_ROUTING,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED })
+ public void setDeviceAbsoluteMultiVolumeAdjustOnlyBehavior(
+ @NonNull AudioDeviceAttributes device,
+ @NonNull List<VolumeInfo> volumes,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OnAudioDeviceVolumeChangedListener vclistener,
+ boolean handlesVolumeAdjustment) {
+ baseSetDeviceAbsoluteMultiVolumeBehavior(device, volumes, executor, vclistener,
+ handlesVolumeAdjustment, AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY);
+ }
+
+ /**
+ * Base method for configuring a device to use absolute volume behavior, or one of its variants.
+ * See {@link AudioManager#AbsoluteDeviceVolumeBehavior} for a list of allowed behaviors.
+ *
+ * @param behavior the variant of absolute device volume behavior to adopt
+ */
+ @RequiresPermission(anyOf = { android.Manifest.permission.MODIFY_AUDIO_ROUTING,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED })
+ private void baseSetDeviceAbsoluteMultiVolumeBehavior(
+ @NonNull AudioDeviceAttributes device,
+ @NonNull List<VolumeInfo> volumes,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OnAudioDeviceVolumeChangedListener vclistener,
+ boolean handlesVolumeAdjustment,
+ @AudioManager.AbsoluteDeviceVolumeBehavior int behavior) {
Objects.requireNonNull(device);
Objects.requireNonNull(volumes);
Objects.requireNonNull(executor);
@@ -253,7 +327,8 @@
mDeviceVolumeListeners.removeIf(info -> info.mDevice.equalTypeAddress(device));
}
mDeviceVolumeListeners.add(listenerInfo);
- mDeviceVolumeDispatcherStub.register(true, device, volumes, handlesVolumeAdjustment);
+ mDeviceVolumeDispatcherStub.register(true, device, volumes, handlesVolumeAdjustment,
+ behavior);
}
}
@@ -375,6 +450,8 @@
return "DEVICE_VOLUME_BEHAVIOR_ABSOLUTE";
case AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE:
return "DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE";
+ case AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY:
+ return "DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY";
default:
return "invalid volume behavior " + behavior;
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index a4d5606..659e3e6 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -6231,6 +6231,15 @@
@SystemApi
public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4;
+ /**
+ * @hide
+ * A variant of {@link #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE} where the host cannot reliably set
+ * the volume percentage of the audio device. Specifically, {@link #setStreamVolume} will have
+ * no effect, or an unreliable effect.
+ */
+ @SystemApi
+ public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY = 5;
+
/** @hide */
@IntDef({
DEVICE_VOLUME_BEHAVIOR_VARIABLE,
@@ -6238,6 +6247,7 @@
DEVICE_VOLUME_BEHAVIOR_FIXED,
DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
+ DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY,
})
@Retention(RetentionPolicy.SOURCE)
public @interface DeviceVolumeBehavior {}
@@ -6250,11 +6260,23 @@
DEVICE_VOLUME_BEHAVIOR_FIXED,
DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
+ DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY,
})
@Retention(RetentionPolicy.SOURCE)
public @interface DeviceVolumeBehaviorState {}
/**
+ * Variants of absolute volume behavior that are set in {@link AudioDeviceVolumeManager}.
+ * @hide
+ */
+ @IntDef({
+ DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
+ DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AbsoluteDeviceVolumeBehavior {}
+
+ /**
* @hide
* Throws IAE on an invalid volume behavior value
* @param volumeBehavior behavior value to check
@@ -6266,6 +6288,7 @@
case DEVICE_VOLUME_BEHAVIOR_FIXED:
case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE:
case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE:
+ case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY:
return;
default:
throw new IllegalArgumentException("Illegal volume behavior " + volumeBehavior);
@@ -6305,6 +6328,16 @@
/**
* @hide
+ * Controls whether DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY may be returned by
+ * getDeviceVolumeBehavior. If this is disabled, DEVICE_VOLUME_BEHAVIOR_FULL is returned
+ * in its place.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ public static final long RETURN_DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY = 240663182L;
+
+ /**
+ * @hide
* Returns the volume device behavior for the given audio device
* @param device the audio device
* @return the volume behavior for the device
@@ -6322,7 +6355,12 @@
// communicate with service
final IAudioService service = getService();
try {
- return service.getDeviceVolumeBehavior(device);
+ int behavior = service.getDeviceVolumeBehavior(device);
+ if (!CompatChanges.isChangeEnabled(RETURN_DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY)
+ && behavior == DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY) {
+ return AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL;
+ }
+ return behavior;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 3e0356f..1c517e7 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -629,12 +629,13 @@
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)")
int[] getActiveAssistantServiceUids();
- @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)")
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING,android.Manifest.permission.BLUETOOTH_PRIVILEGED})")
void registerDeviceVolumeDispatcherForAbsoluteVolume(boolean register,
in IAudioDeviceVolumeDispatcher cb,
in String packageName,
in AudioDeviceAttributes device, in List<VolumeInfo> volumes,
- boolean handlesvolumeAdjustment);
+ boolean handlesvolumeAdjustment,
+ int volumeBehavior);
AudioHalVersionInfo getHalVersion();