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 org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertNotEquals; 21 import static org.testng.Assert.assertThrows; 22 23 import android.media.AudioAttributes; 24 import android.media.AudioManager; 25 import android.media.AudioSystem; 26 import android.media.audiopolicy.AudioProductStrategy; 27 import android.media.audiopolicy.AudioVolumeGroup; 28 import android.util.Log; 29 30 import com.google.common.primitives.Ints; 31 32 import java.util.List; 33 34 public class AudioManagerTest extends AudioVolumesTestBase { 35 private static final String TAG = "AudioManagerTest"; 36 37 //----------------------------------------------------------------- 38 // Test getAudioProductStrategies and validate strategies 39 //----------------------------------------------------------------- testGetAndValidateProductStrategies()40 public void testGetAndValidateProductStrategies() throws Exception { 41 List<AudioProductStrategy> audioProductStrategies = 42 mAudioManager.getAudioProductStrategies(); 43 assertTrue(audioProductStrategies.size() > 0); 44 45 List<AudioVolumeGroup> audioVolumeGroups = mAudioManager.getAudioVolumeGroups(); 46 assertTrue(audioVolumeGroups.size() > 0); 47 48 // Validate Audio Product Strategies 49 for (final AudioProductStrategy audioProductStrategy : audioProductStrategies) { 50 AudioAttributes attributes = audioProductStrategy.getAudioAttributes(); 51 int strategyStreamType = 52 audioProductStrategy.getLegacyStreamTypeForAudioAttributes(attributes); 53 54 assertTrue("Strategy shall support the attributes retrieved from its getter API", 55 audioProductStrategy.supportsAudioAttributes(attributes)); 56 57 int volumeGroupId = 58 audioProductStrategy.getVolumeGroupIdForAudioAttributes(attributes); 59 60 // A strategy must be associated to a volume group 61 assertNotEquals("strategy not assigned to any volume group", 62 volumeGroupId, AudioVolumeGroup.DEFAULT_VOLUME_GROUP); 63 64 // Valid Group ? 65 AudioVolumeGroup audioVolumeGroup = null; 66 for (final AudioVolumeGroup avg : audioVolumeGroups) { 67 if (avg.getId() == volumeGroupId) { 68 audioVolumeGroup = avg; 69 break; 70 } 71 } 72 assertNotNull("Volume Group not found", audioVolumeGroup); 73 74 // Cross check: the group shall have at least one aa / stream types following the 75 // considered strategy 76 boolean strategyAttributesSupported = false; 77 for (final AudioAttributes aa : audioVolumeGroup.getAudioAttributes()) { 78 if (audioProductStrategy.supportsAudioAttributes(aa)) { 79 strategyAttributesSupported = true; 80 break; 81 } 82 } 83 assertTrue("Volume Group and Strategy mismatching", strategyAttributesSupported); 84 85 // Some Product strategy may not have corresponding stream types as they intends 86 // to address volume setting per attributes to avoid adding new stream type 87 // and going on deprecating the stream type even for volume 88 if (strategyStreamType != AudioSystem.STREAM_DEFAULT) { 89 boolean strategStreamTypeSupported = false; 90 for (final int vgStreamType : audioVolumeGroup.getLegacyStreamTypes()) { 91 if (vgStreamType == strategyStreamType) { 92 strategStreamTypeSupported = true; 93 break; 94 } 95 } 96 assertTrue("Volume Group and Strategy mismatching", strategStreamTypeSupported); 97 } 98 } 99 } 100 101 //----------------------------------------------------------------- 102 // Test getAudioVolumeGroups and validate volume groups 103 //----------------------------------------------------------------- 104 testGetAndValidateVolumeGroups()105 public void testGetAndValidateVolumeGroups() throws Exception { 106 List<AudioVolumeGroup> audioVolumeGroups = mAudioManager.getAudioVolumeGroups(); 107 assertTrue(audioVolumeGroups.size() > 0); 108 109 List<AudioProductStrategy> audioProductStrategies = 110 mAudioManager.getAudioProductStrategies(); 111 assertTrue(audioProductStrategies.size() > 0); 112 113 // Validate Audio Volume Groups, check all 114 for (final AudioVolumeGroup audioVolumeGroup : audioVolumeGroups) { 115 List<AudioAttributes> avgAttributes = audioVolumeGroup.getAudioAttributes(); 116 int[] avgStreamTypes = audioVolumeGroup.getLegacyStreamTypes(); 117 118 // for each volume group attributes, find the matching product strategy and ensure 119 // it is linked the considered volume group 120 for (final AudioAttributes aa : avgAttributes) { 121 if (aa.equals(sDefaultAttributes)) { 122 // Some volume groups may not have valid attributes, used for internal 123 // volume management like patch/rerouting 124 // so bailing out strategy retrieval from attributes 125 continue; 126 } 127 boolean isVolumeGroupAssociatedToStrategy = false; 128 for (final AudioProductStrategy strategy : audioProductStrategies) { 129 int groupId = strategy.getVolumeGroupIdForAudioAttributes(aa); 130 if (groupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) { 131 132 assertEquals("Volume Group ID (" + audioVolumeGroup.toString() 133 + "), and Volume group ID associated to Strategy (" 134 + strategy.toString() + ") both supporting attributes " 135 + aa.toString() + " are mismatching", 136 audioVolumeGroup.getId(), groupId); 137 isVolumeGroupAssociatedToStrategy = true; 138 break; 139 } 140 } 141 assertTrue("Volume Group (" + audioVolumeGroup.toString() 142 + ") has no associated strategy for attributes " + aa.toString(), 143 isVolumeGroupAssociatedToStrategy); 144 } 145 146 // for each volume group stream type, find the matching product strategy and ensure 147 // it is linked the considered volume group 148 for (final int avgStreamType : avgStreamTypes) { 149 if (avgStreamType == AudioSystem.STREAM_DEFAULT) { 150 // Some Volume Groups may not have corresponding stream types as they 151 // intends to address volume setting per attributes to avoid adding new 152 // stream type and going on deprecating the stream type even for volume 153 // so bailing out strategy retrieval from stream type 154 continue; 155 } 156 boolean isVolumeGroupAssociatedToStrategy = false; 157 for (final AudioProductStrategy strategy : audioProductStrategies) { 158 Log.i(TAG, "strategy:" + strategy.toString()); 159 int groupId = strategy.getVolumeGroupIdForLegacyStreamType(avgStreamType); 160 if (groupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) { 161 162 assertEquals("Volume Group ID (" + audioVolumeGroup.toString() 163 + "), and Volume group ID associated to Strategy (" 164 + strategy.toString() + ") both supporting stream " 165 + AudioSystem.streamToString(avgStreamType) + "(" 166 + avgStreamType + ") are mismatching", 167 audioVolumeGroup.getId(), groupId); 168 isVolumeGroupAssociatedToStrategy = true; 169 break; 170 } 171 } 172 assertTrue("Volume Group (" + audioVolumeGroup.toString() 173 + ") has no associated strategy for stream " 174 + AudioSystem.streamToString(avgStreamType) + "(" + avgStreamType + ")", 175 isVolumeGroupAssociatedToStrategy); 176 } 177 } 178 } 179 180 //----------------------------------------------------------------- 181 // Test Volume per Attributes setter/getters 182 //----------------------------------------------------------------- testSetGetVolumePerAttributesWithInvalidAttributes()183 public void testSetGetVolumePerAttributesWithInvalidAttributes() throws Exception { 184 AudioAttributes nullAttributes = null; 185 186 assertThrows(NullPointerException.class, 187 () -> mAudioManager.getMaxVolumeIndexForAttributes(nullAttributes)); 188 189 assertThrows(NullPointerException.class, 190 () -> mAudioManager.getMinVolumeIndexForAttributes(nullAttributes)); 191 192 assertThrows(NullPointerException.class, 193 () -> mAudioManager.getVolumeIndexForAttributes(nullAttributes)); 194 195 assertThrows(NullPointerException.class, 196 () -> mAudioManager.setVolumeIndexForAttributes( 197 nullAttributes, 0 /*index*/, 0/*flags*/)); 198 } 199 testSetGetVolumePerAttributes()200 public void testSetGetVolumePerAttributes() throws Exception { 201 for (int usage : AudioAttributes.SDK_USAGES) { 202 if (usage == AudioAttributes.USAGE_UNKNOWN) { 203 continue; 204 } 205 AudioAttributes aaForUsage = new AudioAttributes.Builder().setUsage(usage).build(); 206 int indexMin = 0; 207 int indexMax = 0; 208 int index = 0; 209 Exception ex = null; 210 211 try { 212 indexMax = mAudioManager.getMaxVolumeIndexForAttributes(aaForUsage); 213 } catch (Exception e) { 214 ex = e; // unexpected 215 } 216 assertNull("Exception was thrown for valid attributes", ex); 217 ex = null; 218 try { 219 indexMin = mAudioManager.getMinVolumeIndexForAttributes(aaForUsage); 220 } catch (Exception e) { 221 ex = e; // unexpected 222 } 223 assertNull("Exception was thrown for valid attributes", ex); 224 ex = null; 225 try { 226 index = mAudioManager.getVolumeIndexForAttributes(aaForUsage); 227 } catch (Exception e) { 228 ex = e; // unexpected 229 } 230 assertNull("Exception was thrown for valid attributes", ex); 231 ex = null; 232 try { 233 mAudioManager.setVolumeIndexForAttributes(aaForUsage, indexMin, 0/*flags*/); 234 } catch (Exception e) { 235 ex = e; // unexpected 236 } 237 assertNull("Exception was thrown for valid attributes", ex); 238 239 index = mAudioManager.getVolumeIndexForAttributes(aaForUsage); 240 assertEquals(index, indexMin); 241 242 mAudioManager.setVolumeIndexForAttributes(aaForUsage, indexMax, 0/*flags*/); 243 index = mAudioManager.getVolumeIndexForAttributes(aaForUsage); 244 assertEquals(index, indexMax); 245 } 246 } 247 248 //----------------------------------------------------------------- 249 // Test register/unregister VolumeGroupCallback 250 //----------------------------------------------------------------- testVolumeGroupCallback()251 public void testVolumeGroupCallback() throws Exception { 252 List<AudioVolumeGroup> audioVolumeGroups = mAudioManager.getAudioVolumeGroups(); 253 assertTrue(audioVolumeGroups.size() > 0); 254 255 AudioVolumeGroupCallbackHelper vgCbReceiver = new AudioVolumeGroupCallbackHelper(); 256 mAudioManager.registerVolumeGroupCallback(mContext.getMainExecutor(), vgCbReceiver); 257 258 final List<Integer> publicStreams = Ints.asList(AudioManager.getPublicStreamTypes()); 259 try { 260 // Validate Audio Volume Groups callback reception 261 for (final AudioVolumeGroup audioVolumeGroup : audioVolumeGroups) { 262 int volumeGroupId = audioVolumeGroup.getId(); 263 264 // Set the receiver to filter only the current group callback 265 vgCbReceiver.setExpectedVolumeGroup(volumeGroupId); 266 267 List<AudioAttributes> avgAttributes = audioVolumeGroup.getAudioAttributes(); 268 int[] avgStreamTypes = audioVolumeGroup.getLegacyStreamTypes(); 269 270 int index = 0; 271 int indexMax = 0; 272 int indexMin = 0; 273 274 // Set the volume per attributes (if valid) and wait the callback 275 for (final AudioAttributes aa : avgAttributes) { 276 if (aa.equals(sDefaultAttributes)) { 277 // Some volume groups may not have valid attributes, used for internal 278 // volume management like patch/rerouting 279 // so bailing out strategy retrieval from attributes 280 continue; 281 } 282 index = mAudioManager.getVolumeIndexForAttributes(aa); 283 indexMax = mAudioManager.getMaxVolumeIndexForAttributes(aa); 284 indexMin = mAudioManager.getMinVolumeIndexForAttributes(aa); 285 index = incrementVolumeIndex(index, indexMin, indexMax); 286 287 vgCbReceiver.setExpectedVolumeGroup(volumeGroupId); 288 mAudioManager.setVolumeIndexForAttributes(aa, index, 0/*flags*/); 289 assertTrue(vgCbReceiver.waitForExpectedVolumeGroupChanged( 290 AudioVolumeGroupCallbackHelper.ASYNC_TIMEOUT_MS)); 291 292 int readIndex = mAudioManager.getVolumeIndexForAttributes(aa); 293 assertEquals(readIndex, index); 294 } 295 // Set the volume per stream type (if valid) and wait the callback 296 for (final int avgStreamType : avgStreamTypes) { 297 if (avgStreamType == AudioSystem.STREAM_DEFAULT) { 298 // Some Volume Groups may not have corresponding stream types as they 299 // intends to address volume setting per attributes to avoid adding new 300 // stream type and going on deprecating the stream type even for volume 301 // so bailing out strategy retrieval from stream type 302 continue; 303 } 304 if (!publicStreams.contains(avgStreamType) 305 || avgStreamType == AudioManager.STREAM_ACCESSIBILITY) { 306 // Limit scope of test to public stream that do not require any 307 // permission (e.g. Changing ACCESSIBILITY is subject to permission). 308 continue; 309 } 310 index = mAudioManager.getStreamVolume(avgStreamType); 311 indexMax = mAudioManager.getStreamMaxVolume(avgStreamType); 312 indexMin = mAudioManager.getStreamMinVolumeInt(avgStreamType); 313 index = incrementVolumeIndex(index, indexMin, indexMax); 314 315 vgCbReceiver.setExpectedVolumeGroup(volumeGroupId); 316 mAudioManager.setStreamVolume(avgStreamType, index, 0/*flags*/); 317 assertTrue(vgCbReceiver.waitForExpectedVolumeGroupChanged( 318 AudioVolumeGroupCallbackHelper.ASYNC_TIMEOUT_MS)); 319 320 int readIndex = mAudioManager.getStreamVolume(avgStreamType); 321 assertEquals(index, readIndex); 322 } 323 } 324 } finally { 325 mAudioManager.unregisterVolumeGroupCallback(vgCbReceiver); 326 } 327 } 328 } 329