mOriginalVolumeGroupVolumes = new HashMap<>();
+
+ // Default matches the invalid (empty) attributes from native.
+ // The difference is the input source default which is not aligned between native and java
+ public static final AudioAttributes sDefaultAttributes =
+ AudioProductStrategy.sDefaultAttributes;
+
+ public static final AudioAttributes sInvalidAttributes = new AudioAttributes.Builder().build();
+
+ public final int[] PUBLIC_STREAM_TYPES = { AudioManager.STREAM_VOICE_CALL,
+ AudioManager.STREAM_SYSTEM, AudioManager.STREAM_RING, AudioManager.STREAM_MUSIC,
+ AudioManager.STREAM_ALARM, AudioManager.STREAM_NOTIFICATION,
+ AudioManager.STREAM_DTMF, AudioManager.STREAM_ACCESSIBILITY };
+
+ public AudioVolumesTestBase() {
+ super("com.android.audiopolicytest", AudioPolicyTest.class);
+ }
+
+ /**
+ * Note: must be called with shell permission (MODIFY_AUDIO_ROUTING)
+ */
+ private void storeAllVolumes() {
+ List audioVolumeGroups = mAudioManager.getAudioVolumeGroups();
+ for (final AudioVolumeGroup avg : audioVolumeGroups) {
+ if (avg.getAudioAttributes().isEmpty()) {
+ // some volume group may not supports volume control per attributes
+ // like rerouting/patch since these groups are internal to audio policy manager
+ continue;
+ }
+ AudioAttributes avgAttributes = sDefaultAttributes;
+ for (final AudioAttributes aa : avg.getAudioAttributes()) {
+ if (!aa.equals(AudioProductStrategy.sDefaultAttributes)) {
+ avgAttributes = aa;
+ break;
+ }
+ }
+ if (avgAttributes.equals(sDefaultAttributes)) {
+ // This shall not happen, however, not purpose of this base class.
+ // so bailing out.
+ continue;
+ }
+ mOriginalVolumeGroupVolumes.put(
+ avg.getId(), mAudioManager.getVolumeIndexForAttributes(avgAttributes));
+ }
+ }
+
+ /**
+ * Note: must be called with shell permission (MODIFY_AUDIO_ROUTING)
+ */
+ private void restoreAllVolumes() {
+ List audioVolumeGroups = mAudioManager.getAudioVolumeGroups();
+ for (Map.Entry e : mOriginalVolumeGroupVolumes.entrySet()) {
+ for (final AudioVolumeGroup avg : audioVolumeGroups) {
+ if (avg.getId() == e.getKey()) {
+ assertTrue(!avg.getAudioAttributes().isEmpty());
+ AudioAttributes avgAttributes = sDefaultAttributes;
+ for (final AudioAttributes aa : avg.getAudioAttributes()) {
+ if (!aa.equals(AudioProductStrategy.sDefaultAttributes)) {
+ avgAttributes = aa;
+ break;
+ }
+ }
+ assertTrue(!avgAttributes.equals(sDefaultAttributes));
+ mAudioManager.setVolumeIndexForAttributes(
+ avgAttributes, e.getValue(), AudioManager.FLAG_ALLOW_RINGER_MODES);
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mContext = getActivity();
+ mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+
+ assertEquals(PackageManager.PERMISSION_GRANTED,
+ mContext.checkSelfPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING));
+
+ // Store the original volumes that that they can be recovered in tearDown().
+ mOriginalStreamVolumes.clear();
+ for (int streamType : PUBLIC_STREAM_TYPES) {
+ mOriginalStreamVolumes.put(streamType, mAudioManager.getStreamVolume(streamType));
+ }
+ // Store the original volume per attributes so that they can be recovered in tearDown()
+ mOriginalVolumeGroupVolumes.clear();
+ storeAllVolumes();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+
+ // Recover the volume and the ringer mode that the test may have overwritten.
+ for (Map.Entry e : mOriginalStreamVolumes.entrySet()) {
+ mAudioManager.setStreamVolume(e.getKey(), e.getValue(),
+ AudioManager.FLAG_ALLOW_RINGER_MODES);
+ }
+
+ // Recover the original volume per attributes
+ restoreAllVolumes();
+ }
+
+ public static int resetVolumeIndex(int indexMin, int indexMax) {
+ return (indexMax + indexMin) / 2;
+ }
+
+ public static int incrementVolumeIndex(int index, int indexMin, int indexMax) {
+ return (index + 1 > indexMax) ? resetVolumeIndex(indexMin, indexMax) : ++index;
+ }
+}