1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.audiopolicytest;
18 
19 import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
20 
21 import static com.android.audiopolicytest.AudioVolumeTestUtil.DEFAULT_ATTRIBUTES;
22 import static com.android.audiopolicytest.AudioVolumeTestUtil.incrementVolumeIndex;
23 
24 import static org.junit.Assert.assertEquals;
25 import static org.junit.Assert.assertThrows;
26 import static org.junit.Assert.assertTrue;
27 
28 import android.media.AudioAttributes;
29 import android.media.AudioManager;
30 import android.media.audiopolicy.AudioVolumeGroup;
31 import android.media.audiopolicy.AudioVolumeGroupChangeHandler;
32 import android.platform.test.annotations.Presubmit;
33 
34 import androidx.test.ext.junit.runners.AndroidJUnit4;
35 
36 import org.junit.Before;
37 import org.junit.Rule;
38 import org.junit.Test;
39 import org.junit.runner.RunWith;
40 
41 import java.util.ArrayList;
42 import java.util.List;
43 
44 @Presubmit
45 @RunWith(AndroidJUnit4.class)
46 public class AudioVolumeGroupChangeHandlerTest {
47     private static final String TAG = "AudioVolumeGroupChangeHandlerTest";
48 
49     @Rule
50     public final AudioVolumesTestRule rule = new AudioVolumesTestRule();
51 
52     private AudioManager mAudioManager;
53 
54     @Before
setUp()55     public void setUp() {
56         mAudioManager = getApplicationContext().getSystemService(AudioManager.class);
57     }
58 
59     @Test
testRegisterInvalidCallback()60     public void testRegisterInvalidCallback() {
61         final AudioVolumeGroupChangeHandler audioAudioVolumeGroupChangedHandler =
62                 new AudioVolumeGroupChangeHandler();
63 
64         audioAudioVolumeGroupChangedHandler.init();
65 
66         assertThrows(NullPointerException.class, () -> {
67             AudioManager.VolumeGroupCallback nullCb = null;
68             audioAudioVolumeGroupChangedHandler.registerListener(nullCb);
69         });
70     }
71 
72     @Test
testUnregisterInvalidCallback()73     public void testUnregisterInvalidCallback() {
74         final AudioVolumeGroupChangeHandler audioAudioVolumeGroupChangedHandler =
75                 new AudioVolumeGroupChangeHandler();
76 
77         audioAudioVolumeGroupChangedHandler.init();
78 
79         final AudioVolumeGroupCallbackHelper cb = new AudioVolumeGroupCallbackHelper();
80         audioAudioVolumeGroupChangedHandler.registerListener(cb);
81 
82         assertThrows(NullPointerException.class, () -> {
83             AudioManager.VolumeGroupCallback nullCb = null;
84             audioAudioVolumeGroupChangedHandler.unregisterListener(nullCb);
85         });
86         audioAudioVolumeGroupChangedHandler.unregisterListener(cb);
87     }
88 
89     @Test
testRegisterUnregisterCallback()90     public void testRegisterUnregisterCallback() {
91         final AudioVolumeGroupChangeHandler audioAudioVolumeGroupChangedHandler =
92                 new AudioVolumeGroupChangeHandler();
93 
94         audioAudioVolumeGroupChangedHandler.init();
95         final AudioVolumeGroupCallbackHelper validCb = new AudioVolumeGroupCallbackHelper();
96 
97         // Should not assert, otherwise test will fail
98         audioAudioVolumeGroupChangedHandler.registerListener(validCb);
99 
100         // Should not assert, otherwise test will fail
101         audioAudioVolumeGroupChangedHandler.unregisterListener(validCb);
102     }
103 
104     @Test
testCallbackReceived()105     public void testCallbackReceived() {
106         final AudioVolumeGroupChangeHandler audioAudioVolumeGroupChangedHandler =
107                 new AudioVolumeGroupChangeHandler();
108 
109         audioAudioVolumeGroupChangedHandler.init();
110 
111         final AudioVolumeGroupCallbackHelper validCb = new AudioVolumeGroupCallbackHelper();
112         audioAudioVolumeGroupChangedHandler.registerListener(validCb);
113 
114         List<AudioVolumeGroup> audioVolumeGroups = mAudioManager.getAudioVolumeGroups();
115         assertTrue(audioVolumeGroups.size() > 0);
116 
117         try {
118             for (final AudioVolumeGroup audioVolumeGroup : audioVolumeGroups) {
119                 int volumeGroupId = audioVolumeGroup.getId();
120 
121                 List<AudioAttributes> avgAttributes = audioVolumeGroup.getAudioAttributes();
122                 // Set the volume per attributes (if valid) and wait the callback
123                 if (avgAttributes.size() == 0 || avgAttributes.get(0).equals(DEFAULT_ATTRIBUTES)) {
124                     // Some volume groups may not have valid attributes, used for internal
125                     // volume management like patch/rerouting
126                     // so bailing out strategy retrieval from attributes
127                     continue;
128                 }
129                 final AudioAttributes aa = avgAttributes.get(0);
130 
131                 int index = mAudioManager.getVolumeIndexForAttributes(aa);
132                 int indexMax = mAudioManager.getMaxVolumeIndexForAttributes(aa);
133                 int indexMin = mAudioManager.getMinVolumeIndexForAttributes(aa);
134 
135                 final int indexForAa = incrementVolumeIndex(index, indexMin, indexMax);
136 
137                 // Set the receiver to filter only the current group callback
138                 validCb.setExpectedVolumeGroup(volumeGroupId);
139                 mAudioManager.setVolumeIndexForAttributes(aa, indexForAa, 0/*flags*/);
140                 assertTrue(validCb.waitForExpectedVolumeGroupChanged(
141                         AudioVolumeGroupCallbackHelper.ASYNC_TIMEOUT_MS));
142 
143                 final int readIndex = mAudioManager.getVolumeIndexForAttributes(aa);
144                 assertEquals(readIndex, indexForAa);
145             }
146         } finally {
147             audioAudioVolumeGroupChangedHandler.unregisterListener(validCb);
148         }
149     }
150 
151     @Test
testMultipleCallbackReceived()152     public void testMultipleCallbackReceived() {
153 
154         final AudioVolumeGroupChangeHandler audioAudioVolumeGroupChangedHandler =
155                 new AudioVolumeGroupChangeHandler();
156 
157         audioAudioVolumeGroupChangedHandler.init();
158 
159         final int callbackCount = 10;
160         final List<AudioVolumeGroupCallbackHelper> validCbs =
161                 new ArrayList<AudioVolumeGroupCallbackHelper>();
162         for (int i = 0; i < callbackCount; i++) {
163             validCbs.add(new AudioVolumeGroupCallbackHelper());
164         }
165         for (final AudioVolumeGroupCallbackHelper cb : validCbs) {
166             audioAudioVolumeGroupChangedHandler.registerListener(cb);
167         }
168 
169         List<AudioVolumeGroup> audioVolumeGroups = mAudioManager.getAudioVolumeGroups();
170         assertTrue(audioVolumeGroups.size() > 0);
171 
172         try {
173             for (final AudioVolumeGroup audioVolumeGroup : audioVolumeGroups) {
174                 int volumeGroupId = audioVolumeGroup.getId();
175 
176                 List<AudioAttributes> avgAttributes = audioVolumeGroup.getAudioAttributes();
177                 // Set the volume per attributes (if valid) and wait the callback
178                 if (avgAttributes.size() == 0 || avgAttributes.get(0).equals(DEFAULT_ATTRIBUTES)) {
179                     // Some volume groups may not have valid attributes, used for internal
180                     // volume management like patch/rerouting
181                     // so bailing out strategy retrieval from attributes
182                     continue;
183                 }
184                 AudioAttributes aa = avgAttributes.get(0);
185 
186                 int index = mAudioManager.getVolumeIndexForAttributes(aa);
187                 int indexMax = mAudioManager.getMaxVolumeIndexForAttributes(aa);
188                 int indexMin = mAudioManager.getMinVolumeIndexForAttributes(aa);
189 
190                 final int indexForAa = incrementVolumeIndex(index, indexMin, indexMax);
191 
192                 // Set the receiver to filter only the current group callback
193                 for (final AudioVolumeGroupCallbackHelper cb : validCbs) {
194                     cb.setExpectedVolumeGroup(volumeGroupId);
195                 }
196                 mAudioManager.setVolumeIndexForAttributes(aa, indexForAa, 0/*flags*/);
197 
198                 for (final AudioVolumeGroupCallbackHelper cb : validCbs) {
199                     assertTrue(cb.waitForExpectedVolumeGroupChanged(
200                             AudioVolumeGroupCallbackHelper.ASYNC_TIMEOUT_MS));
201                 }
202                 int readIndex = mAudioManager.getVolumeIndexForAttributes(aa);
203                 assertEquals(readIndex, indexForAa);
204             }
205         } finally {
206             for (final AudioVolumeGroupCallbackHelper cb : validCbs) {
207                 audioAudioVolumeGroupChangedHandler.unregisterListener(cb);
208             }
209         }
210     }
211 }
212