Merge "AudioDeviceVolumeManager and VolumeInfo API changes" into tm-qpr-dev
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index b618969..ec100c2 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -115,6 +115,7 @@
import android.location.ICountryDetector;
import android.location.ILocationManager;
import android.location.LocationManager;
+import android.media.AudioDeviceVolumeManager;
import android.media.AudioManager;
import android.media.MediaFrameworkInitializer;
import android.media.MediaFrameworkPlatformInitializer;
@@ -339,6 +340,13 @@
return new AudioManager(ctx);
}});
+ registerService(Context.AUDIO_DEVICE_VOLUME_SERVICE, AudioDeviceVolumeManager.class,
+ new CachedServiceFetcher<AudioDeviceVolumeManager>() {
+ @Override
+ public AudioDeviceVolumeManager createService(ContextImpl ctx) {
+ return new AudioDeviceVolumeManager(ctx);
+ }});
+
registerService(Context.MEDIA_ROUTER_SERVICE, MediaRouter.class,
new CachedServiceFetcher<MediaRouter>() {
@Override
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index fce23cf..77ca48a 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3846,6 +3846,7 @@
WIFI_RTT_RANGING_SERVICE,
NSD_SERVICE,
AUDIO_SERVICE,
+ AUDIO_DEVICE_VOLUME_SERVICE,
AUTH_SERVICE,
FINGERPRINT_SERVICE,
//@hide: FACE_SERVICE,
@@ -4687,6 +4688,17 @@
public static final String AUDIO_SERVICE = "audio";
/**
+ * @hide
+ * Use with {@link #getSystemService(String)} to retrieve a
+ * {@link android.media.AudioDeviceVolumeManager} for handling management of audio device
+ * (e.g. speaker, USB headset) volume.
+ *
+ * @see #getSystemService(String)
+ * @see android.media.AudioDeviceVolumeManager
+ */
+ public static final String AUDIO_DEVICE_VOLUME_SERVICE = "audio_device_volume";
+
+ /**
* Use with {@link #getSystemService(String)} to retrieve a {@link
* android.media.MediaTranscodingManager} for transcoding media.
*
diff --git a/media/java/android/media/AudioDeviceVolumeManager.java b/media/java/android/media/AudioDeviceVolumeManager.java
index c708876..4aee9eb 100644
--- a/media/java/android/media/AudioDeviceVolumeManager.java
+++ b/media/java/android/media/AudioDeviceVolumeManager.java
@@ -41,8 +41,7 @@
*/
public class AudioDeviceVolumeManager {
- // define when using Log.*
- //private static final String TAG = "AudioDeviceVolumeManager";
+ private static final String TAG = "AudioDeviceVolumeManager";
/** Indicates no special treatment in the handling of the volume adjustment */
public static final int ADJUST_MODE_NORMAL = 0;
@@ -62,11 +61,15 @@
private static IAudioService sService;
private final @NonNull String mPackageName;
- private final @Nullable String mAttributionTag;
- public AudioDeviceVolumeManager(Context context) {
+ /**
+ * @hide
+ * Constructor
+ * @param context the Context for the device volume operations
+ */
+ public AudioDeviceVolumeManager(@NonNull Context context) {
+ Objects.requireNonNull(context);
mPackageName = context.getApplicationContext().getOpPackageName();
- mAttributionTag = context.getApplicationContext().getAttributionTag();
}
/**
@@ -308,13 +311,36 @@
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public void setDeviceVolume(@NonNull VolumeInfo vi, @NonNull AudioDeviceAttributes ada) {
try {
- getService().setDeviceVolume(vi, ada, mPackageName, mAttributionTag);
+ getService().setDeviceVolume(vi, ada, mPackageName);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
}
/**
+ * @hide
+ * Returns the volume on the given audio device for the given volume information.
+ * For instance if using a {@link VolumeInfo} configured for {@link AudioManager#STREAM_ALARM},
+ * it will return the alarm volume. When no volume index has ever been set for the given
+ * device, the default volume will be returned (the volume setting that would have been
+ * applied if playback for that use case had started).
+ * @param vi the volume information, only stream-based volumes are supported. Information
+ * other than the stream type is ignored.
+ * @param ada the device for which volume is to be retrieved
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public @NonNull VolumeInfo getDeviceVolume(@NonNull VolumeInfo vi,
+ @NonNull AudioDeviceAttributes ada) {
+ try {
+ return getService().getDeviceVolume(vi, ada, mPackageName);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return VolumeInfo.getDefaultVolumeInfo();
+ }
+
+ /**
+ * @hide
* Return human-readable name for volume behavior
* @param behavior one of the volume behaviors defined in AudioManager
* @return a string for the given behavior
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index e7eda3e..798688e 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1212,7 +1212,13 @@
}
}
- private static boolean isPublicStreamType(int streamType) {
+ /**
+ * @hide
+ * Checks whether a stream type is part of the public SDK
+ * @param streamType
+ * @return true if the stream type is available in SDK
+ */
+ public static boolean isPublicStreamType(int streamType) {
switch (streamType) {
case STREAM_VOICE_CALL:
case STREAM_SYSTEM:
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 90eb9e6..ad933e0 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -99,7 +99,10 @@
in String callingPackage, in String attributionTag);
void setDeviceVolume(in VolumeInfo vi, in AudioDeviceAttributes ada,
- in String callingPackage, in String attributionTag);
+ in String callingPackage);
+
+ VolumeInfo getDeviceVolume(in VolumeInfo vi, in AudioDeviceAttributes ada,
+ in String callingPackage);
oneway void handleVolumeKey(in KeyEvent event, boolean isOnTv,
String callingPackage, String caller);
diff --git a/media/java/android/media/VolumeInfo.java b/media/java/android/media/VolumeInfo.java
index c61b0e5..bc91a09 100644
--- a/media/java/android/media/VolumeInfo.java
+++ b/media/java/android/media/VolumeInfo.java
@@ -27,7 +27,6 @@
import android.os.ServiceManager;
import android.util.Log;
-import java.util.List;
import java.util.Objects;
/**
@@ -35,8 +34,9 @@
* A class to represent type of volume information.
* Can be used to represent volume associated with a stream type or {@link AudioVolumeGroup}.
* Volume index is optional when used to represent a category of volume.
- * Index ranges are supported too, making the representation of volume changes agnostic to the
- * range (e.g. can be used to map BT A2DP absolute volume range to internal range).
+ * Volume ranges are supported too, making the representation of volume changes agnostic
+ * regarding the range of values that are supported (e.g. can be used to map BT A2DP absolute
+ * volume range to internal range).
*
* Note: this class is not yet part of the SystemApi but is intended to be gradually introduced
* particularly in parts of the audio framework that suffer from code ambiguity when
@@ -46,25 +46,27 @@
private static final String TAG = "VolumeInfo";
private final boolean mUsesStreamType; // false implies AudioVolumeGroup is used
+ private final boolean mHasMuteCommand;
private final boolean mIsMuted;
private final int mVolIndex;
private final int mMinVolIndex;
private final int mMaxVolIndex;
- private final int mVolGroupId;
- private final int mStreamType;
+ private final @Nullable AudioVolumeGroup mVolGroup;
+ private final @AudioManager.PublicStreamTypes int mStreamType;
private static IAudioService sService;
private static VolumeInfo sDefaultVolumeInfo;
- private VolumeInfo(boolean usesStreamType, boolean isMuted, int volIndex,
- int minVolIndex, int maxVolIndex,
- int volGroupId, int streamType) {
+ private VolumeInfo(boolean usesStreamType, boolean hasMuteCommand, boolean isMuted,
+ int volIndex, int minVolIndex, int maxVolIndex,
+ AudioVolumeGroup volGroup, int streamType) {
mUsesStreamType = usesStreamType;
+ mHasMuteCommand = hasMuteCommand;
mIsMuted = isMuted;
mVolIndex = volIndex;
mMinVolIndex = minVolIndex;
mMaxVolIndex = maxVolIndex;
- mVolGroupId = volGroupId;
+ mVolGroup = volGroup;
mStreamType = streamType;
}
@@ -81,8 +83,10 @@
/**
* Returns the associated stream type, or will throw if {@link #hasStreamType()} returned false.
* @return a stream type value, see AudioManager.STREAM_*
+ * @throws IllegalStateException when called on a VolumeInfo not configured for
+ * stream types.
*/
- public int getStreamType() {
+ public @AudioManager.PublicStreamTypes int getStreamType() {
if (!mUsesStreamType) {
throw new IllegalStateException("VolumeInfo doesn't use stream types");
}
@@ -101,24 +105,28 @@
/**
* Returns the associated volume group, or will throw if {@link #hasVolumeGroup()} returned
* false.
- * @return the volume group corresponding to this VolumeInfo, or null if an error occurred
- * in the volume group management
+ * @return the volume group corresponding to this VolumeInfo
+ * @throws IllegalStateException when called on a VolumeInfo not configured for
+ * volume groups.
*/
- public @Nullable AudioVolumeGroup getVolumeGroup() {
+ public @NonNull AudioVolumeGroup getVolumeGroup() {
if (mUsesStreamType) {
throw new IllegalStateException("VolumeInfo doesn't use AudioVolumeGroup");
}
- List<AudioVolumeGroup> volGroups = AudioVolumeGroup.getAudioVolumeGroups();
- for (AudioVolumeGroup group : volGroups) {
- if (group.getId() == mVolGroupId) {
- return group;
- }
- }
- return null;
+ return mVolGroup;
}
/**
- * Returns whether this instance is conveying a mute state.
+ * Return whether this instance is conveying a mute state
+ * @return true if the muted state was explicitly set for this instance
+ */
+ public boolean hasMuteCommand() {
+ return mHasMuteCommand;
+ }
+
+ /**
+ * Returns whether this instance is conveying a mute state that was explicitly set
+ * by {@link Builder#setMuted(boolean)}, false otherwise
* @return true if the volume state is muted
*/
public boolean isMuted() {
@@ -185,18 +193,21 @@
*/
public static final class Builder {
private boolean mUsesStreamType = true; // false implies AudioVolumeGroup is used
- private int mStreamType = AudioManager.STREAM_MUSIC;
+ private @AudioManager.PublicStreamTypes int mStreamType = AudioManager.STREAM_MUSIC;
+ private boolean mHasMuteCommand = false;
private boolean mIsMuted = false;
private int mVolIndex = INDEX_NOT_SET;
private int mMinVolIndex = INDEX_NOT_SET;
private int mMaxVolIndex = INDEX_NOT_SET;
- private int mVolGroupId = -Integer.MIN_VALUE;
+ private @Nullable AudioVolumeGroup mVolGroup;
/**
* Builder constructor for stream type-based VolumeInfo
*/
- public Builder(int streamType) {
- // TODO validate stream type
+ public Builder(@AudioManager.PublicStreamTypes int streamType) {
+ if (!AudioManager.isPublicStreamType(streamType)) {
+ throw new IllegalArgumentException("Not a valid public stream type " + streamType);
+ }
mUsesStreamType = true;
mStreamType = streamType;
}
@@ -208,7 +219,7 @@
Objects.requireNonNull(volGroup);
mUsesStreamType = false;
mStreamType = -Integer.MIN_VALUE;
- mVolGroupId = volGroup.getId();
+ mVolGroup = volGroup;
}
/**
@@ -219,11 +230,12 @@
Objects.requireNonNull(info);
mUsesStreamType = info.mUsesStreamType;
mStreamType = info.mStreamType;
+ mHasMuteCommand = info.mHasMuteCommand;
mIsMuted = info.mIsMuted;
mVolIndex = info.mVolIndex;
mMinVolIndex = info.mMinVolIndex;
mMaxVolIndex = info.mMaxVolIndex;
- mVolGroupId = info.mVolGroupId;
+ mVolGroup = info.mVolGroup;
}
/**
@@ -232,6 +244,7 @@
* @return the same builder instance
*/
public @NonNull Builder setMuted(boolean isMuted) {
+ mHasMuteCommand = true;
mIsMuted = isMuted;
return this;
}
@@ -241,7 +254,6 @@
* @param volIndex a 0 or greater value, or {@link #INDEX_NOT_SET} if unknown
* @return the same builder instance
*/
- // TODO should we allow muted true + volume index set? (useful when toggling mute on/off?)
public @NonNull Builder setVolumeIndex(int volIndex) {
if (volIndex != INDEX_NOT_SET && volIndex < 0) {
throw new IllegalArgumentException("Volume index cannot be negative");
@@ -296,9 +308,9 @@
throw new IllegalArgumentException("Min volume index:" + mMinVolIndex
+ " greater than max index:" + mMaxVolIndex);
}
- return new VolumeInfo(mUsesStreamType, mIsMuted,
+ return new VolumeInfo(mUsesStreamType, mHasMuteCommand, mIsMuted,
mVolIndex, mMinVolIndex, mMaxVolIndex,
- mVolGroupId, mStreamType);
+ mVolGroup, mStreamType);
}
}
@@ -306,8 +318,8 @@
// Parcelable
@Override
public int hashCode() {
- return Objects.hash(mUsesStreamType, mStreamType, mIsMuted,
- mVolIndex, mMinVolIndex, mMaxVolIndex, mVolGroupId);
+ return Objects.hash(mUsesStreamType, mHasMuteCommand, mStreamType, mIsMuted,
+ mVolIndex, mMinVolIndex, mMaxVolIndex, mVolGroup);
}
@Override
@@ -318,19 +330,20 @@
VolumeInfo that = (VolumeInfo) o;
return ((mUsesStreamType == that.mUsesStreamType)
&& (mStreamType == that.mStreamType)
- && (mIsMuted == that.mIsMuted)
- && (mVolIndex == that.mVolIndex)
- && (mMinVolIndex == that.mMinVolIndex)
- && (mMaxVolIndex == that.mMaxVolIndex)
- && (mVolGroupId == that.mVolGroupId));
+ && (mHasMuteCommand == that.mHasMuteCommand)
+ && (mIsMuted == that.mIsMuted)
+ && (mVolIndex == that.mVolIndex)
+ && (mMinVolIndex == that.mMinVolIndex)
+ && (mMaxVolIndex == that.mMaxVolIndex)
+ && Objects.equals(mVolGroup, that.mVolGroup));
}
@Override
public String toString() {
return new String("VolumeInfo:"
+ (mUsesStreamType ? (" streamType:" + mStreamType)
- : (" volGroupId" + mVolGroupId))
- + " muted:" + mIsMuted
+ : (" volGroup:" + mVolGroup))
+ + (mHasMuteCommand ? (" muted:" + mIsMuted) : ("[no mute cmd]"))
+ ((mVolIndex != INDEX_NOT_SET) ? (" volIndex:" + mVolIndex) : "")
+ ((mMinVolIndex != INDEX_NOT_SET) ? (" min:" + mMinVolIndex) : "")
+ ((mMaxVolIndex != INDEX_NOT_SET) ? (" max:" + mMaxVolIndex) : ""));
@@ -345,21 +358,29 @@
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeBoolean(mUsesStreamType);
dest.writeInt(mStreamType);
+ dest.writeBoolean(mHasMuteCommand);
dest.writeBoolean(mIsMuted);
dest.writeInt(mVolIndex);
dest.writeInt(mMinVolIndex);
dest.writeInt(mMaxVolIndex);
- dest.writeInt(mVolGroupId);
+ if (!mUsesStreamType) {
+ mVolGroup.writeToParcel(dest, 0 /*ignored*/);
+ }
}
private VolumeInfo(@NonNull Parcel in) {
mUsesStreamType = in.readBoolean();
mStreamType = in.readInt();
+ mHasMuteCommand = in.readBoolean();
mIsMuted = in.readBoolean();
mVolIndex = in.readInt();
mMinVolIndex = in.readInt();
mMaxVolIndex = in.readInt();
- mVolGroupId = in.readInt();
+ if (!mUsesStreamType) {
+ mVolGroup = AudioVolumeGroup.CREATOR.createFromParcel(in);
+ } else {
+ mVolGroup = null;
+ }
}
public static final @NonNull Parcelable.Creator<VolumeInfo> CREATOR =
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 4a01c61..83a77bd 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -3599,6 +3599,18 @@
}
}
+ // TODO enforce MODIFY_AUDIO_SYSTEM_SETTINGS when defined
+ private void enforceModifyAudioRoutingOrSystemSettingsPermission() {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ != PackageManager.PERMISSION_GRANTED
+ /*&& mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS)
+ != PackageManager.PERMISSION_DENIED*/) {
+ throw new SecurityException(
+ "Missing MODIFY_AUDIO_ROUTING or MODIFY_AUDIO_SYSTEM_SETTINGS permission");
+ }
+ }
+
private void enforceAccessUltrasoundPermission() {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.ACCESS_ULTRASOUND)
!= PackageManager.PERMISSION_GRANTED) {
@@ -3703,10 +3715,12 @@
}
/** @see AudioDeviceVolumeManager#setDeviceVolume(VolumeInfo, AudioDeviceAttributes)
- * Part of service interface, check permissions and parameters here */
+ * Part of service interface, check permissions and parameters here
+ * Note calling package is for logging purposes only, not to be trusted
+ */
public void setDeviceVolume(@NonNull VolumeInfo vi, @NonNull AudioDeviceAttributes ada,
- @NonNull String callingPackage, @Nullable String attributionTag) {
- enforceModifyAudioRoutingPermission();
+ @NonNull String callingPackage) {
+ enforceModifyAudioRoutingOrSystemSettingsPermission();
Objects.requireNonNull(vi);
Objects.requireNonNull(ada);
Objects.requireNonNull(callingPackage);
@@ -3719,8 +3733,20 @@
return;
}
int index = vi.getVolumeIndex();
- if (index == VolumeInfo.INDEX_NOT_SET) {
- throw new IllegalArgumentException("changing device volume requires a volume index");
+ if (index == VolumeInfo.INDEX_NOT_SET && !vi.hasMuteCommand()) {
+ throw new IllegalArgumentException(
+ "changing device volume requires a volume index or mute command");
+ }
+
+ // TODO handle unmuting of current audio device
+ // if a stream is not muted but the VolumeInfo is for muting, set the volume index
+ // for the device to min volume
+ if (vi.hasMuteCommand() && vi.isMuted() && !isStreamMute(vi.getStreamType())) {
+ setStreamVolumeWithAttributionInt(vi.getStreamType(),
+ mStreamStates[vi.getStreamType()].getMinIndex(),
+ /*flags*/ 0,
+ ada, callingPackage, null);
+ return;
}
if (vi.getMinVolumeIndex() == VolumeInfo.INDEX_NOT_SET
@@ -3742,7 +3768,7 @@
}
}
setStreamVolumeWithAttributionInt(vi.getStreamType(), index, /*flags*/ 0,
- ada, callingPackage, attributionTag);
+ ada, callingPackage, null);
}
/** Retain API for unsupported app usage */
@@ -4648,6 +4674,40 @@
}
}
+ /**
+ * @see AudioDeviceVolumeManager#getDeviceVolume(VolumeInfo, AudioDeviceAttributes)
+ */
+ public @NonNull VolumeInfo getDeviceVolume(@NonNull VolumeInfo vi,
+ @NonNull AudioDeviceAttributes ada, @NonNull String callingPackage) {
+ enforceModifyAudioRoutingOrSystemSettingsPermission();
+ Objects.requireNonNull(vi);
+ Objects.requireNonNull(ada);
+ Objects.requireNonNull(callingPackage);
+ if (!vi.hasStreamType()) {
+ Log.e(TAG, "Unsupported non-stream type based VolumeInfo", new Exception());
+ return getDefaultVolumeInfo();
+ }
+
+ int streamType = vi.getStreamType();
+ final VolumeInfo.Builder vib = new VolumeInfo.Builder(vi);
+ vib.setMinVolumeIndex((mStreamStates[streamType].mIndexMin + 5) / 10);
+ vib.setMaxVolumeIndex((mStreamStates[streamType].mIndexMax + 5) / 10);
+ synchronized (VolumeStreamState.class) {
+ final int index;
+ if (isFixedVolumeDevice(ada.getInternalType())) {
+ index = (mStreamStates[streamType].mIndexMax + 5) / 10;
+ } else {
+ index = (mStreamStates[streamType].getIndex(ada.getInternalType()) + 5) / 10;
+ }
+ vib.setVolumeIndex(index);
+ // only set as a mute command if stream muted
+ if (mStreamStates[streamType].mIsMuted) {
+ vib.setMuted(true);
+ }
+ return vib.build();
+ }
+ }
+
/** @see AudioManager#getStreamMaxVolume(int) */
public int getStreamMaxVolume(int streamType) {
ensureValidStreamType(streamType);
@@ -4686,7 +4746,6 @@
sDefaultVolumeInfo = new VolumeInfo.Builder(AudioSystem.STREAM_MUSIC)
.setMinVolumeIndex(getStreamMinVolume(AudioSystem.STREAM_MUSIC))
.setMaxVolumeIndex(getStreamMaxVolume(AudioSystem.STREAM_MUSIC))
- .setMuted(false)
.build();
}
return sDefaultVolumeInfo;
diff --git a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceVolumeManagerTest.java b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceVolumeManagerTest.java
index 7acb6d6..64af296 100644
--- a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceVolumeManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceVolumeManagerTest.java
@@ -27,18 +27,18 @@
import android.media.AudioSystem;
import android.media.VolumeInfo;
import android.os.test.TestLooper;
+import android.util.Log;
import androidx.test.InstrumentationRegistry;
+import junit.framework.Assert;
+
import org.junit.Before;
import org.junit.Test;
public class AudioDeviceVolumeManagerTest {
private static final String TAG = "AudioDeviceVolumeManagerTest";
- private static final AudioDeviceAttributes DEVICE_SPEAKER_OUT = new AudioDeviceAttributes(
- AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, "");
-
private Context mContext;
private String mPackageName;
private AudioSystemAdapter mSpyAudioSystem;
@@ -84,14 +84,20 @@
final AudioDeviceAttributes usbDevice = new AudioDeviceAttributes(
/*native type*/ AudioSystem.DEVICE_OUT_USB_DEVICE, /*address*/ "bla");
- mAudioService.setDeviceVolume(volMin, usbDevice, mPackageName, TAG);
+ mAudioService.setDeviceVolume(volMin, usbDevice, mPackageName);
mTestLooper.dispatchAll();
verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
AudioManager.STREAM_MUSIC, minIndex, AudioSystem.DEVICE_OUT_USB_DEVICE);
- mAudioService.setDeviceVolume(volMid, usbDevice, mPackageName, TAG);
+ mAudioService.setDeviceVolume(volMid, usbDevice, mPackageName);
mTestLooper.dispatchAll();
verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
AudioManager.STREAM_MUSIC, midIndex, AudioSystem.DEVICE_OUT_USB_DEVICE);
+
+ final VolumeInfo vi = mAudioService.getDeviceVolume(volMin, usbDevice, mPackageName);
+ Assert.assertEquals("getDeviceVolume doesn't return expected value in " + vi
+ + " after setting " + volMid,
+ (volMid.getMaxVolumeIndex() - volMid.getMinVolumeIndex()) / 2,
+ (vi.getMaxVolumeIndex() - vi.getMinVolumeIndex()) / 2);
}
}