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);
     }
 }