Merge changes from topic "abs-vol-adjust-only"
* changes:
Add adjust-only absolute volume behavior.
Fix incorrect return value from getDeviceVolumeBehavior
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 39ebdc0..76e9f09 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -6757,6 +6757,7 @@
field public static final int AUDIOFOCUS_FLAG_LOCK = 4; // 0x4
field public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 2; // 0x2
field public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3; // 0x3
+ field public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY = 5; // 0x5
field public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4; // 0x4
field public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2; // 0x2
field public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1; // 0x1
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 39d965f..7de3abc3 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();
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index c01424d..e55bddb 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -692,6 +692,7 @@
// Devices where the framework sends a full scale audio signal, and controls the volume of
// the external audio system separately.
+ // For possible volume behaviors, see {@link AudioManager.AbsoluteDeviceVolumeBehavior}.
Map<Integer, AbsoluteVolumeDeviceInfo> mAbsoluteVolumeDeviceInfoMap = new ArrayMap<>();
/**
@@ -702,13 +703,19 @@
private final List<VolumeInfo> mVolumeInfos;
private final IAudioDeviceVolumeDispatcher mCallback;
private final boolean mHandlesVolumeAdjustment;
+ private @AudioManager.AbsoluteDeviceVolumeBehavior int mDeviceVolumeBehavior;
- private AbsoluteVolumeDeviceInfo(AudioDeviceAttributes device, List<VolumeInfo> volumeInfos,
- IAudioDeviceVolumeDispatcher callback, boolean handlesVolumeAdjustment) {
+ private AbsoluteVolumeDeviceInfo(
+ AudioDeviceAttributes device,
+ List<VolumeInfo> volumeInfos,
+ IAudioDeviceVolumeDispatcher callback,
+ boolean handlesVolumeAdjustment,
+ @AudioManager.AbsoluteDeviceVolumeBehavior int behavior) {
this.mDevice = device;
this.mVolumeInfos = volumeInfos;
this.mCallback = callback;
this.mHandlesVolumeAdjustment = handlesVolumeAdjustment;
+ this.mDeviceVolumeBehavior = behavior;
}
/**
@@ -7057,7 +7064,8 @@
public void registerDeviceVolumeDispatcherForAbsoluteVolume(boolean register,
IAudioDeviceVolumeDispatcher cb, String packageName,
AudioDeviceAttributes device, List<VolumeInfo> volumes,
- boolean handlesVolumeAdjustment) {
+ boolean handlesVolumeAdjustment,
+ @AudioManager.AbsoluteDeviceVolumeBehavior int deviceVolumeBehavior) {
// verify permissions
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
!= PackageManager.PERMISSION_GRANTED
@@ -7073,13 +7081,16 @@
int deviceOut = device.getInternalType();
if (register) {
AbsoluteVolumeDeviceInfo info = new AbsoluteVolumeDeviceInfo(
- device, volumes, cb, handlesVolumeAdjustment);
- boolean volumeBehaviorChanged =
- removeAudioSystemDeviceOutFromFullVolumeDevices(deviceOut)
- | removeAudioSystemDeviceOutFromFixedVolumeDevices(deviceOut)
- | (addAudioSystemDeviceOutToAbsVolumeDevices(deviceOut, info) == null);
+ device, volumes, cb, handlesVolumeAdjustment, deviceVolumeBehavior);
+ AbsoluteVolumeDeviceInfo oldInfo = mAbsoluteVolumeDeviceInfoMap.get(deviceOut);
+ boolean volumeBehaviorChanged = (oldInfo == null)
+ || (oldInfo.mDeviceVolumeBehavior != deviceVolumeBehavior);
if (volumeBehaviorChanged) {
- dispatchDeviceVolumeBehavior(device, AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
+ removeAudioSystemDeviceOutFromFullVolumeDevices(deviceOut);
+ removeAudioSystemDeviceOutFromFixedVolumeDevices(deviceOut);
+ addAudioSystemDeviceOutToAbsVolumeDevices(deviceOut, info);
+
+ dispatchDeviceVolumeBehavior(device, deviceVolumeBehavior);
}
// Update stream volumes to the given device, if specified in a VolumeInfo.
// Mute state is not updated because it is stream-wide - the only way to mute a
@@ -7171,6 +7182,7 @@
!= null);
break;
case AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE:
+ case AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY:
case AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE:
throw new IllegalArgumentException("Absolute volume unsupported for now");
}
@@ -7214,11 +7226,6 @@
// AudioDeviceInfo.convertDeviceTypeToInternalDevice()
final int audioSystemDeviceOut = device.getInternalType();
- int setDeviceVolumeBehavior = retrieveStoredDeviceVolumeBehavior(audioSystemDeviceOut);
- if (setDeviceVolumeBehavior != AudioManager.DEVICE_VOLUME_BEHAVIOR_UNSET) {
- return setDeviceVolumeBehavior;
- }
-
// setDeviceVolumeBehavior has not been explicitly called for the device type. Deduce the
// current volume behavior.
if (mFullVolumeDevices.contains(audioSystemDeviceOut)) {
@@ -7230,8 +7237,11 @@
if (mAbsVolumeMultiModeCaseDevices.contains(audioSystemDeviceOut)) {
return AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE;
}
- if (isAbsoluteVolumeDevice(audioSystemDeviceOut)
- || isA2dpAbsoluteVolumeDevice(audioSystemDeviceOut)
+ if (mAbsoluteVolumeDeviceInfoMap.containsKey(audioSystemDeviceOut)) {
+ return mAbsoluteVolumeDeviceInfoMap.get(audioSystemDeviceOut).mDeviceVolumeBehavior;
+ }
+
+ if (isA2dpAbsoluteVolumeDevice(audioSystemDeviceOut)
|| AudioSystem.isLeAudioDeviceType(audioSystemDeviceOut)) {
return AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE;
}
@@ -10680,6 +10690,13 @@
pw.println();
}
+ private Set<Integer> getAbsoluteVolumeDevicesWithBehavior(int behavior) {
+ return mAbsoluteVolumeDeviceInfoMap.entrySet().stream()
+ .filter(entry -> entry.getValue().mDeviceVolumeBehavior == behavior)
+ .map(Map.Entry::getKey)
+ .collect(Collectors.toSet());
+ }
+
private String dumpDeviceTypes(@NonNull Set<Integer> deviceTypes) {
Iterator<Integer> it = deviceTypes.iterator();
if (!it.hasNext()) {
@@ -10728,14 +10745,20 @@
pw.print(" mNotifAliasRing="); pw.println(mNotifAliasRing);
pw.print(" mFixedVolumeDevices="); pw.println(dumpDeviceTypes(mFixedVolumeDevices));
pw.print(" mFullVolumeDevices="); pw.println(dumpDeviceTypes(mFullVolumeDevices));
- pw.print(" mAbsoluteVolumeDevices.keySet()="); pw.println(dumpDeviceTypes(
- mAbsoluteVolumeDeviceInfoMap.keySet()));
+ pw.print(" absolute volume devices="); pw.println(dumpDeviceTypes(
+ getAbsoluteVolumeDevicesWithBehavior(
+ AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE)));
+ pw.print(" adjust-only absolute volume devices="); pw.println(dumpDeviceTypes(
+ getAbsoluteVolumeDevicesWithBehavior(
+ AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY)));
pw.print(" mExtVolumeController="); pw.println(mExtVolumeController);
pw.print(" mHdmiAudioSystemClient="); pw.println(mHdmiAudioSystemClient);
pw.print(" mHdmiPlaybackClient="); pw.println(mHdmiPlaybackClient);
pw.print(" mHdmiTvClient="); pw.println(mHdmiTvClient);
pw.print(" mHdmiSystemAudioSupported="); pw.println(mHdmiSystemAudioSupported);
- pw.print(" mHdmiCecVolumeControlEnabled="); pw.println(mHdmiCecVolumeControlEnabled);
+ synchronized (mHdmiClientLock) {
+ pw.print(" mHdmiCecVolumeControlEnabled="); pw.println(mHdmiCecVolumeControlEnabled);
+ }
pw.print(" mIsCallScreeningModeSupported="); pw.println(mIsCallScreeningModeSupported);
pw.print(" mic mute FromSwitch=" + mMicMuteFromSwitch
+ " FromRestrictions=" + mMicMuteFromRestrictions
@@ -12780,11 +12803,14 @@
}
/**
- * Returns whether the input device uses absolute volume behavior. This is distinct
- * from Bluetooth A2DP absolute volume behavior ({@link #isA2dpAbsoluteVolumeDevice}).
+ * Returns whether the input device uses absolute volume behavior, including its variants.
+ * For included volume behaviors, see {@link AudioManager.AbsoluteDeviceVolumeBehavior}.
+ *
+ * This is distinct from Bluetooth A2DP absolute volume behavior
+ * ({@link #isA2dpAbsoluteVolumeDevice}).
*/
private boolean isAbsoluteVolumeDevice(int deviceType) {
- return mAbsoluteVolumeDeviceInfoMap.containsKey(deviceType);
+ return mAbsoluteVolumeDeviceInfoMap.containsKey(deviceType);
}
/**
@@ -12888,13 +12914,15 @@
return mFullVolumeDevices.remove(audioSystemDeviceOut);
}
- private AbsoluteVolumeDeviceInfo addAudioSystemDeviceOutToAbsVolumeDevices(
- int audioSystemDeviceOut, AbsoluteVolumeDeviceInfo info) {
+ private void addAudioSystemDeviceOutToAbsVolumeDevices(int audioSystemDeviceOut,
+ AbsoluteVolumeDeviceInfo info) {
if (DEBUG_VOL) {
Log.d(TAG, "Adding DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut)
- + " from mAbsoluteVolumeDeviceInfoMap");
+ + " to mAbsoluteVolumeDeviceInfoMap with behavior "
+ + AudioDeviceVolumeManager.volumeBehaviorName(info.mDeviceVolumeBehavior)
+ );
}
- return mAbsoluteVolumeDeviceInfoMap.put(audioSystemDeviceOut, info);
+ mAbsoluteVolumeDeviceInfoMap.put(audioSystemDeviceOut, info);
}
private AbsoluteVolumeDeviceInfo removeAudioSystemDeviceOutFromAbsVolumeDevices(
diff --git a/services/tests/servicestests/src/com/android/server/audio/AbsoluteVolumeBehaviorTest.java b/services/tests/servicestests/src/com/android/server/audio/AbsoluteVolumeBehaviorTest.java
index 38093de..7c736c7 100644
--- a/services/tests/servicestests/src/com/android/server/audio/AbsoluteVolumeBehaviorTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/AbsoluteVolumeBehaviorTest.java
@@ -40,13 +40,20 @@
import androidx.test.InstrumentationRegistry;
+import libcore.junit.util.compat.CoreCompatChangeRule;
+
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TestRule;
import java.util.Collections;
import java.util.List;
public class AbsoluteVolumeBehaviorTest {
+ @Rule
+ public TestRule compatChangeRule = new CoreCompatChangeRule();
+
private static final String TAG = "AbsoluteVolumeBehaviorTest";
private static final AudioDeviceAttributes DEVICE_SPEAKER_OUT = new AudioDeviceAttributes(
@@ -92,7 +99,30 @@
new VolumeInfo.Builder(AudioManager.STREAM_MUSIC).build());
mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true,
- mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT, volumes, true);
+ mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT, volumes, true,
+ AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
+ mTestLooper.dispatchAll();
+
+ assertThat(mAudioService.getDeviceVolumeBehavior(DEVICE_SPEAKER_OUT))
+ .isEqualTo(AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
+ }
+
+ /**
+ * Tests that getDeviceVolumeBehavior returns the correct volume behavior, even if
+ * a different volume behavior was previously persisted via setDeviceVolumeBehavior
+ */
+ @Test
+ public void registerDispatcherAfterSetDeviceVolumeBehavior_setsVolumeBehaviorToAbsolute() {
+ List<VolumeInfo> volumes = Collections.singletonList(
+ new VolumeInfo.Builder(AudioManager.STREAM_MUSIC).build());
+
+ mAudioService.setDeviceVolumeBehavior(DEVICE_SPEAKER_OUT,
+ AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL, mPackageName);
+ mTestLooper.dispatchAll();
+
+ mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true,
+ mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT, volumes, true,
+ AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
mTestLooper.dispatchAll();
assertThat(mAudioService.getDeviceVolumeBehavior(DEVICE_SPEAKER_OUT))
@@ -109,7 +139,8 @@
.build());
mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true,
- mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT, volumes, true);
+ mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT, volumes, true,
+ AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
mTestLooper.dispatchAll();
assertThat(mAudioService.getStreamVolume(AudioManager.STREAM_MUSIC))
@@ -124,11 +155,13 @@
new VolumeInfo.Builder(AudioManager.STREAM_MUSIC).build());
mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true,
- mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT, volumes, true);
+ mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT, volumes, true,
+ AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
mTestLooper.dispatchAll();
mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(false,
- mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT, volumes, true);
+ mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT, volumes, true,
+ AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
mTestLooper.dispatchAll();
assertThat(mAudioService.getDeviceVolumeBehavior(DEVICE_SPEAKER_OUT))
@@ -147,7 +180,8 @@
new VolumeInfo.Builder(AudioManager.STREAM_MUSIC).build());
mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true,
- mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT, volumes, true);
+ mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT, volumes, true,
+ AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
mTestLooper.dispatchAll();
mAudioService.setDeviceVolumeBehavior(DEVICE_SPEAKER_OUT,
@@ -171,7 +205,8 @@
mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true,
mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT,
- Collections.singletonList(volumeInfo), true);
+ Collections.singletonList(volumeInfo), true,
+ AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
mTestLooper.dispatchAll();
// Set stream volume without FLAG_ABSOLUTE_VOLUME
@@ -194,7 +229,8 @@
mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true,
mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT,
- Collections.singletonList(volumeInfo), true);
+ Collections.singletonList(volumeInfo), true,
+ AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
mTestLooper.dispatchAll();
// Set stream volume with FLAG_ABSOLUTE_VOLUME
@@ -218,7 +254,8 @@
// Register dispatcher with handlesVolumeAdjustment = true
mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true,
mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT,
- Collections.singletonList(volumeInfo), true);
+ Collections.singletonList(volumeInfo), true,
+ AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
mTestLooper.dispatchAll();
// Adjust stream volume without FLAG_ABSOLUTE_VOLUME
@@ -247,7 +284,8 @@
// Register dispatcher with handlesVolumeAdjustment = false
mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true,
mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT,
- Collections.singletonList(volumeInfo), false);
+ Collections.singletonList(volumeInfo), false,
+ AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
mTestLooper.dispatchAll();
// Adjust stream volume without FLAG_ABSOLUTE_VOLUME
@@ -274,7 +312,8 @@
mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true,
mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT,
- Collections.singletonList(volumeInfo), true);
+ Collections.singletonList(volumeInfo), true,
+ AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
mTestLooper.dispatchAll();
// Adjust stream volume with FLAG_ABSOLUTE_VOLUME set
@@ -289,4 +328,38 @@
verify(mMockDispatcher, never()).dispatchDeviceVolumeAdjusted(eq(DEVICE_SPEAKER_OUT), any(),
anyInt(), anyInt());
}
+
+ @Test
+ public void switchAbsoluteVolumeBehaviorToAdjustOnly_onlyDispatchesVolumeChangeForNewListener()
+ throws RemoteException {
+ VolumeInfo volumeInfo = new VolumeInfo.Builder(AudioManager.STREAM_MUSIC)
+ .setMinVolumeIndex(0)
+ .setMaxVolumeIndex(250)
+ .setVolumeIndex(0)
+ .build();
+
+ mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true,
+ mMockDispatcher, mPackageName, DEVICE_SPEAKER_OUT,
+ Collections.singletonList(volumeInfo), false,
+ AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE);
+ mTestLooper.dispatchAll();
+
+ IAudioDeviceVolumeDispatcher.Stub mMockAdjustOnlyAbsoluteVolumeDispatcher =
+ mock(IAudioDeviceVolumeDispatcher.Stub.class);
+ mAudioService.registerDeviceVolumeDispatcherForAbsoluteVolume(true,
+ mMockAdjustOnlyAbsoluteVolumeDispatcher, mPackageName, DEVICE_SPEAKER_OUT,
+ Collections.singletonList(volumeInfo), false,
+ AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY);
+ mTestLooper.dispatchAll();
+
+ // Set stream volume without FLAG_ABSOLUTE_VOLUME
+ mAudioService.setStreamVolume(AudioManager.STREAM_MUSIC, 15, 0, mPackageName);
+ mTestLooper.dispatchAll();
+
+ // Volume change not dispatched for absolute volume listener
+ verify(mMockDispatcher, never()).dispatchDeviceVolumeChanged(eq(DEVICE_SPEAKER_OUT), any());
+ // Volume changed dispatched for adjust-only absolute volume listener
+ verify(mMockAdjustOnlyAbsoluteVolumeDispatcher).dispatchDeviceVolumeChanged(
+ DEVICE_SPEAKER_OUT, new VolumeInfo.Builder(volumeInfo).setVolumeIndex(150).build());
+ }
}