• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 android.media.AudioManager.STREAM_ACCESSIBILITY;
20 import static android.media.AudioManager.STREAM_ALARM;
21 import static android.media.AudioManager.STREAM_DTMF;
22 import static android.media.AudioManager.STREAM_MUSIC;
23 import static android.media.AudioManager.STREAM_NOTIFICATION;
24 import static android.media.AudioManager.STREAM_RING;
25 import static android.media.AudioManager.STREAM_SYSTEM;
26 import static android.media.AudioManager.STREAM_VOICE_CALL;
27 
28 import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
29 
30 import static com.android.audiopolicytest.AudioVolumeTestUtil.DEFAULT_ATTRIBUTES;
31 import static com.android.audiopolicytest.AudioVolumeTestUtil.incrementVolumeIndex;
32 
33 import static org.junit.Assert.assertEquals;
34 import static org.junit.Assert.assertNotEquals;
35 import static org.junit.Assert.assertNotNull;
36 import static org.junit.Assert.assertNull;
37 import static org.junit.Assert.assertThrows;
38 import static org.junit.Assert.assertTrue;
39 
40 import android.content.Context;
41 import android.media.AudioAttributes;
42 import android.media.AudioManager;
43 import android.media.AudioSystem;
44 import android.media.IAudioService;
45 import android.media.audiopolicy.AudioProductStrategy;
46 import android.media.audiopolicy.AudioVolumeGroup;
47 import android.os.IBinder;
48 import android.os.ServiceManager;
49 import android.platform.test.annotations.Presubmit;
50 import android.util.Log;
51 
52 import androidx.test.ext.junit.runners.AndroidJUnit4;
53 
54 import com.google.common.primitives.Ints;
55 
56 import org.junit.Before;
57 import org.junit.Rule;
58 import org.junit.Test;
59 import org.junit.runner.RunWith;
60 
61 import java.util.List;
62 
63 @Presubmit
64 @RunWith(AndroidJUnit4.class)
65 public class AudioManagerTest {
66     private static final String TAG = "AudioManagerTest";
67 
68     private AudioManager mAudioManager;
69 
70     private static final int[] PUBLIC_STREAM_TYPES = {
71             STREAM_VOICE_CALL,
72             STREAM_SYSTEM,
73             STREAM_RING,
74             STREAM_MUSIC,
75             STREAM_ALARM,
76             STREAM_NOTIFICATION,
77             STREAM_DTMF,
78             STREAM_ACCESSIBILITY,
79     };
80 
81     @Rule
82     public final AudioVolumesTestRule rule = new AudioVolumesTestRule();
83 
84     @Before
setUp()85     public void setUp() {
86         mAudioManager = getApplicationContext().getSystemService(AudioManager.class);
87     }
88 
89     //-----------------------------------------------------------------
90     // Test getAudioProductStrategies and validate strategies
91     //-----------------------------------------------------------------
92     @Test
testGetAndValidateProductStrategies()93     public void testGetAndValidateProductStrategies() {
94         List<AudioProductStrategy> audioProductStrategies =
95                 mAudioManager.getAudioProductStrategies();
96         assertTrue(audioProductStrategies.size() > 0);
97 
98         List<AudioVolumeGroup> audioVolumeGroups = mAudioManager.getAudioVolumeGroups();
99         assertTrue(audioVolumeGroups.size() > 0);
100 
101         // Validate Audio Product Strategies
102         for (final AudioProductStrategy audioProductStrategy : audioProductStrategies) {
103             AudioAttributes attributes = audioProductStrategy.getAudioAttributes();
104             int strategyStreamType =
105                     audioProductStrategy.getLegacyStreamTypeForAudioAttributes(attributes);
106 
107             assertTrue("Strategy shall support the attributes retrieved from its getter API",
108                     audioProductStrategy.supportsAudioAttributes(attributes));
109 
110             int volumeGroupId =
111                     audioProductStrategy.getVolumeGroupIdForAudioAttributes(attributes);
112 
113             // A strategy must be associated to a volume group
114             assertNotEquals("strategy not assigned to any volume group",
115                     volumeGroupId, AudioVolumeGroup.DEFAULT_VOLUME_GROUP);
116 
117             // Valid Group ?
118             AudioVolumeGroup audioVolumeGroup = null;
119             for (final AudioVolumeGroup avg : audioVolumeGroups) {
120                 if (avg.getId() == volumeGroupId) {
121                     audioVolumeGroup = avg;
122                     break;
123                 }
124             }
125             assertNotNull("Volume Group not found", audioVolumeGroup);
126 
127             // Cross check: the group shall have at least one aa / stream types following the
128             // considered strategy
129             boolean strategyAttributesSupported = false;
130             for (final AudioAttributes aa : audioVolumeGroup.getAudioAttributes()) {
131                 if (audioProductStrategy.supportsAudioAttributes(aa)) {
132                     strategyAttributesSupported = true;
133                     break;
134                 }
135             }
136             assertTrue("Volume Group and Strategy mismatching", strategyAttributesSupported);
137 
138             // Some Product strategy may not have corresponding stream types as they intends
139             // to address volume setting per attributes to avoid adding new stream type
140             // and going on deprecating the stream type even for volume
141             if (strategyStreamType != AudioSystem.STREAM_DEFAULT) {
142                 boolean strategStreamTypeSupported = false;
143                 for (final int vgStreamType : audioVolumeGroup.getLegacyStreamTypes()) {
144                     if (vgStreamType == strategyStreamType) {
145                         strategStreamTypeSupported = true;
146                         break;
147                     }
148                 }
149                 assertTrue("Volume Group and Strategy mismatching", strategStreamTypeSupported);
150             }
151         }
152     }
153 
154     //-----------------------------------------------------------------
155     // Test getAudioVolumeGroups and validate volume groups
156     //-----------------------------------------------------------------
157     @Test
testGetAndValidateVolumeGroups()158     public void testGetAndValidateVolumeGroups() {
159         List<AudioVolumeGroup> audioVolumeGroups = mAudioManager.getAudioVolumeGroups();
160         assertTrue(audioVolumeGroups.size() > 0);
161 
162         List<AudioProductStrategy> audioProductStrategies =
163                 mAudioManager.getAudioProductStrategies();
164         assertTrue(audioProductStrategies.size() > 0);
165 
166         // Validate Audio Volume Groups, check all
167         for (final AudioVolumeGroup audioVolumeGroup : audioVolumeGroups) {
168             List<AudioAttributes> avgAttributes = audioVolumeGroup.getAudioAttributes();
169             int[] avgStreamTypes = audioVolumeGroup.getLegacyStreamTypes();
170 
171             // for each volume group attributes, find the matching product strategy and ensure
172             // it is linked the considered volume group
173             for (final AudioAttributes aa : avgAttributes) {
174                 if (aa.equals(DEFAULT_ATTRIBUTES)) {
175                     // Some volume groups may not have valid attributes, used for internal
176                     // volume management like patch/rerouting
177                     // so bailing out strategy retrieval from attributes
178                     continue;
179                 }
180                 boolean isVolumeGroupAssociatedToStrategy = false;
181                 for (final AudioProductStrategy strategy : audioProductStrategies) {
182                     int groupId = strategy.getVolumeGroupIdForAudioAttributes(aa);
183                     if (groupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) {
184 
185                         assertEquals("Volume Group ID (" + audioVolumeGroup.toString()
186                                 + "), and Volume group ID associated to Strategy ("
187                                 + strategy.toString() + ") both supporting attributes "
188                                 + aa.toString() + " are mismatching",
189                                 audioVolumeGroup.getId(), groupId);
190                         isVolumeGroupAssociatedToStrategy = true;
191                         break;
192                     }
193                 }
194                 assertTrue("Volume Group (" + audioVolumeGroup.toString()
195                         + ") has no associated strategy for attributes " + aa.toString(),
196                         isVolumeGroupAssociatedToStrategy);
197             }
198 
199             // for each volume group stream type, find the matching product strategy and ensure
200             // it is linked the considered volume group
201             for (final int avgStreamType : avgStreamTypes) {
202                 if (avgStreamType == AudioSystem.STREAM_DEFAULT) {
203                     // Some Volume Groups may not have corresponding stream types as they
204                     // intends to address volume setting per attributes to avoid adding new
205                     //  stream type and going on deprecating the stream type even for volume
206                     // so bailing out strategy retrieval from stream type
207                     continue;
208                 }
209                 boolean isVolumeGroupAssociatedToStrategy = false;
210                 for (final AudioProductStrategy strategy : audioProductStrategies) {
211                     Log.i(TAG, "strategy:" + strategy.toString());
212                     int groupId = strategy.getVolumeGroupIdForLegacyStreamType(avgStreamType);
213                     if (groupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) {
214 
215                         assertEquals("Volume Group ID (" + audioVolumeGroup.toString()
216                                 + "), and Volume group ID associated to Strategy ("
217                                 + strategy.toString() + ") both supporting stream "
218                                 + AudioSystem.streamToString(avgStreamType) + "("
219                                 + avgStreamType + ") are mismatching",
220                                 audioVolumeGroup.getId(), groupId);
221                         isVolumeGroupAssociatedToStrategy = true;
222                         break;
223                     }
224                 }
225                 assertTrue("Volume Group (" + audioVolumeGroup.toString()
226                         + ") has no associated strategy for stream "
227                         + AudioSystem.streamToString(avgStreamType) + "(" + avgStreamType + ")",
228                         isVolumeGroupAssociatedToStrategy);
229             }
230         }
231     }
232 
233     //-----------------------------------------------------------------
234     // Test getStreamVolume consistency with AudioService
235     //-----------------------------------------------------------------
236     @Test
getStreamMinMaxVolume_consistentWithAs()237     public void getStreamMinMaxVolume_consistentWithAs() throws Exception {
238         IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
239         IAudioService service = IAudioService.Stub.asInterface(b);
240 
241         for (int streamType : PUBLIC_STREAM_TYPES) {
242             assertEquals(service.getStreamMinVolume(streamType),
243                     mAudioManager.getStreamMinVolume(streamType));
244             assertEquals(service.getStreamMaxVolume(streamType),
245                     mAudioManager.getStreamMaxVolume(streamType));
246         }
247     }
248 
249     @Test
getStreamVolume_consistentWithAs()250     public void getStreamVolume_consistentWithAs() throws Exception {
251         IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
252         IAudioService service = IAudioService.Stub.asInterface(b);
253 
254         for (int streamType : PUBLIC_STREAM_TYPES) {
255             assertEquals(service.getStreamVolume(streamType),
256                     mAudioManager.getStreamVolume(streamType));
257         }
258     }
259 
260     //-----------------------------------------------------------------
261     // Test Volume per Attributes setter/getters
262     //-----------------------------------------------------------------
263     @Test
testSetGetVolumePerAttributesWithInvalidAttributes()264     public void testSetGetVolumePerAttributesWithInvalidAttributes() throws Exception {
265         AudioAttributes nullAttributes = null;
266 
267         assertThrows(NullPointerException.class,
268                 () -> mAudioManager.getMaxVolumeIndexForAttributes(nullAttributes));
269 
270         assertThrows(NullPointerException.class,
271                 () -> mAudioManager.getMinVolumeIndexForAttributes(nullAttributes));
272 
273         assertThrows(NullPointerException.class,
274                 () -> mAudioManager.getVolumeIndexForAttributes(nullAttributes));
275 
276         assertThrows(NullPointerException.class,
277                 () -> mAudioManager.setVolumeIndexForAttributes(
278                         nullAttributes, 0 /*index*/, 0/*flags*/));
279     }
280 
281     @Test
testSetGetVolumePerAttributes()282     public void testSetGetVolumePerAttributes() {
283         for (int usage : AudioAttributes.getSdkUsages()) {
284             if (usage == AudioAttributes.USAGE_UNKNOWN) {
285                 continue;
286             }
287             AudioAttributes aaForUsage = new AudioAttributes.Builder().setUsage(usage).build();
288             int indexMin = 0;
289             int indexMax = 0;
290             int index = 0;
291             Exception ex = null;
292 
293             try {
294                 indexMax = mAudioManager.getMaxVolumeIndexForAttributes(aaForUsage);
295             } catch (Exception e) {
296                 ex = e; // unexpected
297             }
298             assertNull("Exception was thrown for valid attributes", ex);
299             ex = null;
300             try {
301                 indexMin = mAudioManager.getMinVolumeIndexForAttributes(aaForUsage);
302             } catch (Exception e) {
303                 ex = e; // unexpected
304             }
305             assertNull("Exception was thrown for valid attributes", ex);
306             ex = null;
307             try {
308                 index = mAudioManager.getVolumeIndexForAttributes(aaForUsage);
309             } catch (Exception e) {
310                 ex = e; // unexpected
311             }
312             assertNull("Exception was thrown for valid attributes", ex);
313             ex = null;
314             try {
315                 mAudioManager.setVolumeIndexForAttributes(aaForUsage, indexMin, 0/*flags*/);
316             } catch (Exception e) {
317                 ex = e; // unexpected
318             }
319             assertNull("Exception was thrown for valid attributes", ex);
320 
321             index = mAudioManager.getVolumeIndexForAttributes(aaForUsage);
322             assertEquals(index, indexMin);
323 
324             mAudioManager.setVolumeIndexForAttributes(aaForUsage, indexMax, 0/*flags*/);
325             index = mAudioManager.getVolumeIndexForAttributes(aaForUsage);
326             assertEquals(index, indexMax);
327         }
328     }
329 
330     //-----------------------------------------------------------------
331     // Test register/unregister VolumeGroupCallback
332     //-----------------------------------------------------------------
333     @Test
testVolumeGroupCallback()334     public void testVolumeGroupCallback() {
335         List<AudioVolumeGroup> audioVolumeGroups = mAudioManager.getAudioVolumeGroups();
336         assertTrue(audioVolumeGroups.size() > 0);
337 
338         AudioVolumeGroupCallbackHelper vgCbReceiver = new AudioVolumeGroupCallbackHelper();
339         mAudioManager.registerVolumeGroupCallback(getApplicationContext().getMainExecutor(),
340                 vgCbReceiver);
341 
342         final List<Integer> publicStreams = Ints.asList(AudioManager.getPublicStreamTypes());
343         try {
344             // Validate Audio Volume Groups callback reception
345             for (final AudioVolumeGroup audioVolumeGroup : audioVolumeGroups) {
346                 int volumeGroupId = audioVolumeGroup.getId();
347 
348                 // Set the receiver to filter only the current group callback
349                 vgCbReceiver.setExpectedVolumeGroup(volumeGroupId);
350 
351                 List<AudioAttributes> avgAttributes = audioVolumeGroup.getAudioAttributes();
352                 int[] avgStreamTypes = audioVolumeGroup.getLegacyStreamTypes();
353 
354                 int index = 0;
355                 int indexMax = 0;
356                 int indexMin = 0;
357 
358                 // Set the volume per attributes (if valid) and wait the callback
359                 for (final AudioAttributes aa : avgAttributes) {
360                     if (aa.equals(DEFAULT_ATTRIBUTES)) {
361                         // Some volume groups may not have valid attributes, used for internal
362                         // volume management like patch/rerouting
363                         // so bailing out strategy retrieval from attributes
364                         continue;
365                     }
366                     index = mAudioManager.getVolumeIndexForAttributes(aa);
367                     indexMax = mAudioManager.getMaxVolumeIndexForAttributes(aa);
368                     indexMin = mAudioManager.getMinVolumeIndexForAttributes(aa);
369                     index = incrementVolumeIndex(index, indexMin, indexMax);
370 
371                     vgCbReceiver.setExpectedVolumeGroup(volumeGroupId);
372                     mAudioManager.setVolumeIndexForAttributes(aa, index, 0/*flags*/);
373                     assertTrue(vgCbReceiver.waitForExpectedVolumeGroupChanged(
374                             AudioVolumeGroupCallbackHelper.ASYNC_TIMEOUT_MS));
375 
376                     int readIndex = mAudioManager.getVolumeIndexForAttributes(aa);
377                     assertEquals(readIndex, index);
378                 }
379                 // Set the volume per stream type (if valid) and wait the callback
380                 for (final int avgStreamType : avgStreamTypes) {
381                     if (avgStreamType == AudioSystem.STREAM_DEFAULT) {
382                         // Some Volume Groups may not have corresponding stream types as they
383                         // intends to address volume setting per attributes to avoid adding new
384                         // stream type and going on deprecating the stream type even for volume
385                         // so bailing out strategy retrieval from stream type
386                         continue;
387                     }
388                     if (!publicStreams.contains(avgStreamType)
389                             || avgStreamType == AudioManager.STREAM_ACCESSIBILITY) {
390                         // Limit scope of test to public stream that do not require any
391                         // permission (e.g. Changing ACCESSIBILITY is subject to permission).
392                         continue;
393                     }
394                     index = mAudioManager.getStreamVolume(avgStreamType);
395                     indexMax = mAudioManager.getStreamMaxVolume(avgStreamType);
396                     indexMin = mAudioManager.getStreamMinVolumeInt(avgStreamType);
397                     index = incrementVolumeIndex(index, indexMin, indexMax);
398 
399                     vgCbReceiver.setExpectedVolumeGroup(volumeGroupId);
400                     mAudioManager.setStreamVolume(avgStreamType, index, 0/*flags*/);
401                     assertTrue(vgCbReceiver.waitForExpectedVolumeGroupChanged(
402                             AudioVolumeGroupCallbackHelper.ASYNC_TIMEOUT_MS));
403 
404                     int readIndex = mAudioManager.getStreamVolume(avgStreamType);
405                     assertEquals(index, readIndex);
406                 }
407             }
408         } finally {
409             mAudioManager.unregisterVolumeGroupCallback(vgCbReceiver);
410         }
411     }
412 }
413