Merge "AudioManager: Add functional tests for productstrategy/volumegroup" into rvc-dev am: 5fb2147af2
Change-Id: I70963769ee5d6184a7cc34bcb654d76dbd5c15c8
This commit is contained in:
commit
48b9be33e1
17
media/tests/AudioPolicyTest/Android.bp
Normal file
17
media/tests/AudioPolicyTest/Android.bp
Normal file
@ -0,0 +1,17 @@
|
||||
android_test {
|
||||
name: "audiopolicytest",
|
||||
srcs: ["**/*.java"],
|
||||
libs: [
|
||||
"android.test.runner",
|
||||
"android.test.base",
|
||||
],
|
||||
static_libs: [
|
||||
"mockito-target-minus-junit4",
|
||||
"androidx.test.rules",
|
||||
"android-ex-camera2",
|
||||
"testng",
|
||||
],
|
||||
platform_apis: true,
|
||||
certificate: "platform",
|
||||
resource_dirs: ["res"],
|
||||
}
|
45
media/tests/AudioPolicyTest/AndroidManifest.xml
Normal file
45
media/tests/AudioPolicyTest/AndroidManifest.xml
Normal file
@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2020 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.audiopolicytest">
|
||||
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_ROUTING" />
|
||||
<uses-permission android:name="android.permission.CHANGE_ACCESSIBILITY_VOLUME" />
|
||||
|
||||
<application>
|
||||
<uses-library android:name="android.test.runner" />
|
||||
<activity android:label="@string/app_name" android:name="AudioPolicyTest"
|
||||
android:screenOrientation="landscape">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
<!--instrumentation android:name=".AudioPolicyTestRunner"
|
||||
android:targetPackage="com.android.audiopolicytest"
|
||||
android:label="AudioManager policy oriented integration tests InstrumentationRunner">
|
||||
</instrumentation-->
|
||||
|
||||
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
|
||||
android:targetPackage="com.android.audiopolicytest"
|
||||
android:label="AudioManager policy oriented integration tests InstrumentationRunner">
|
||||
</instrumentation>
|
||||
</manifest>
|
27
media/tests/AudioPolicyTest/AndroidTest.xml
Normal file
27
media/tests/AudioPolicyTest/AndroidTest.xml
Normal file
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2020 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<configuration description="Runs Media Framework Tests">
|
||||
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
|
||||
<option name="test-file-name" value="audiopolicytest.apk" />
|
||||
</target_preparer>
|
||||
|
||||
<option name="test-tag" value="AudioPolicyTest" />
|
||||
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
|
||||
<option name="package" value="com.android.audiopolicytest" />
|
||||
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
|
||||
<option name="hidden-api-checks" value="false"/>
|
||||
</test>
|
||||
</configuration>
|
21
media/tests/AudioPolicyTest/res/layout/audiopolicytest.xml
Normal file
21
media/tests/AudioPolicyTest/res/layout/audiopolicytest.xml
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2020 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical">
|
||||
</LinearLayout>
|
5
media/tests/AudioPolicyTest/res/values/strings.xml
Normal file
5
media/tests/AudioPolicyTest/res/values/strings.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- name of the app [CHAR LIMIT=25]-->
|
||||
<string name="app_name">Audio Policy APIs Tests</string>
|
||||
</resources>
|
@ -0,0 +1,328 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.audiopolicytest;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.testng.Assert.assertThrows;
|
||||
|
||||
import android.media.AudioAttributes;
|
||||
import android.media.AudioManager;
|
||||
import android.media.AudioSystem;
|
||||
import android.media.audiopolicy.AudioProductStrategy;
|
||||
import android.media.audiopolicy.AudioVolumeGroup;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.common.primitives.Ints;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class AudioManagerTest extends AudioVolumesTestBase {
|
||||
private static final String TAG = "AudioManagerTest";
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Test getAudioProductStrategies and validate strategies
|
||||
//-----------------------------------------------------------------
|
||||
public void testGetAndValidateProductStrategies() throws Exception {
|
||||
List<AudioProductStrategy> audioProductStrategies =
|
||||
mAudioManager.getAudioProductStrategies();
|
||||
assertTrue(audioProductStrategies.size() > 0);
|
||||
|
||||
List<AudioVolumeGroup> audioVolumeGroups = mAudioManager.getAudioVolumeGroups();
|
||||
assertTrue(audioVolumeGroups.size() > 0);
|
||||
|
||||
// Validate Audio Product Strategies
|
||||
for (final AudioProductStrategy audioProductStrategy : audioProductStrategies) {
|
||||
AudioAttributes attributes = audioProductStrategy.getAudioAttributes();
|
||||
int strategyStreamType =
|
||||
audioProductStrategy.getLegacyStreamTypeForAudioAttributes(attributes);
|
||||
|
||||
assertTrue("Strategy shall support the attributes retrieved from its getter API",
|
||||
audioProductStrategy.supportsAudioAttributes(attributes));
|
||||
|
||||
int volumeGroupId =
|
||||
audioProductStrategy.getVolumeGroupIdForAudioAttributes(attributes);
|
||||
|
||||
// A strategy must be associated to a volume group
|
||||
assertNotEquals("strategy not assigned to any volume group",
|
||||
volumeGroupId, AudioVolumeGroup.DEFAULT_VOLUME_GROUP);
|
||||
|
||||
// Valid Group ?
|
||||
AudioVolumeGroup audioVolumeGroup = null;
|
||||
for (final AudioVolumeGroup avg : audioVolumeGroups) {
|
||||
if (avg.getId() == volumeGroupId) {
|
||||
audioVolumeGroup = avg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertNotNull("Volume Group not found", audioVolumeGroup);
|
||||
|
||||
// Cross check: the group shall have at least one aa / stream types following the
|
||||
// considered strategy
|
||||
boolean strategyAttributesSupported = false;
|
||||
for (final AudioAttributes aa : audioVolumeGroup.getAudioAttributes()) {
|
||||
if (audioProductStrategy.supportsAudioAttributes(aa)) {
|
||||
strategyAttributesSupported = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertTrue("Volume Group and Strategy mismatching", strategyAttributesSupported);
|
||||
|
||||
// Some Product strategy may not have corresponding stream types as they intends
|
||||
// to address volume setting per attributes to avoid adding new stream type
|
||||
// and going on deprecating the stream type even for volume
|
||||
if (strategyStreamType != AudioSystem.STREAM_DEFAULT) {
|
||||
boolean strategStreamTypeSupported = false;
|
||||
for (final int vgStreamType : audioVolumeGroup.getLegacyStreamTypes()) {
|
||||
if (vgStreamType == strategyStreamType) {
|
||||
strategStreamTypeSupported = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertTrue("Volume Group and Strategy mismatching", strategStreamTypeSupported);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Test getAudioVolumeGroups and validate volume groups
|
||||
//-----------------------------------------------------------------
|
||||
|
||||
public void testGetAndValidateVolumeGroups() throws Exception {
|
||||
List<AudioVolumeGroup> audioVolumeGroups = mAudioManager.getAudioVolumeGroups();
|
||||
assertTrue(audioVolumeGroups.size() > 0);
|
||||
|
||||
List<AudioProductStrategy> audioProductStrategies =
|
||||
mAudioManager.getAudioProductStrategies();
|
||||
assertTrue(audioProductStrategies.size() > 0);
|
||||
|
||||
// Validate Audio Volume Groups, check all
|
||||
for (final AudioVolumeGroup audioVolumeGroup : audioVolumeGroups) {
|
||||
List<AudioAttributes> avgAttributes = audioVolumeGroup.getAudioAttributes();
|
||||
int[] avgStreamTypes = audioVolumeGroup.getLegacyStreamTypes();
|
||||
|
||||
// for each volume group attributes, find the matching product strategy and ensure
|
||||
// it is linked the considered volume group
|
||||
for (final AudioAttributes aa : avgAttributes) {
|
||||
if (aa.equals(sDefaultAttributes)) {
|
||||
// Some volume groups may not have valid attributes, used for internal
|
||||
// volume management like patch/rerouting
|
||||
// so bailing out strategy retrieval from attributes
|
||||
continue;
|
||||
}
|
||||
boolean isVolumeGroupAssociatedToStrategy = false;
|
||||
for (final AudioProductStrategy strategy : audioProductStrategies) {
|
||||
int groupId = strategy.getVolumeGroupIdForAudioAttributes(aa);
|
||||
if (groupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) {
|
||||
|
||||
assertEquals("Volume Group ID (" + audioVolumeGroup.toString()
|
||||
+ "), and Volume group ID associated to Strategy ("
|
||||
+ strategy.toString() + ") both supporting attributes "
|
||||
+ aa.toString() + " are mismatching",
|
||||
audioVolumeGroup.getId(), groupId);
|
||||
isVolumeGroupAssociatedToStrategy = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertTrue("Volume Group (" + audioVolumeGroup.toString()
|
||||
+ ") has no associated strategy for attributes " + aa.toString(),
|
||||
isVolumeGroupAssociatedToStrategy);
|
||||
}
|
||||
|
||||
// for each volume group stream type, find the matching product strategy and ensure
|
||||
// it is linked the considered volume group
|
||||
for (final int avgStreamType : avgStreamTypes) {
|
||||
if (avgStreamType == AudioSystem.STREAM_DEFAULT) {
|
||||
// Some Volume Groups may not have corresponding stream types as they
|
||||
// intends to address volume setting per attributes to avoid adding new
|
||||
// stream type and going on deprecating the stream type even for volume
|
||||
// so bailing out strategy retrieval from stream type
|
||||
continue;
|
||||
}
|
||||
boolean isVolumeGroupAssociatedToStrategy = false;
|
||||
for (final AudioProductStrategy strategy : audioProductStrategies) {
|
||||
Log.i(TAG, "strategy:" + strategy.toString());
|
||||
int groupId = strategy.getVolumeGroupIdForLegacyStreamType(avgStreamType);
|
||||
if (groupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) {
|
||||
|
||||
assertEquals("Volume Group ID (" + audioVolumeGroup.toString()
|
||||
+ "), and Volume group ID associated to Strategy ("
|
||||
+ strategy.toString() + ") both supporting stream "
|
||||
+ AudioSystem.streamToString(avgStreamType) + "("
|
||||
+ avgStreamType + ") are mismatching",
|
||||
audioVolumeGroup.getId(), groupId);
|
||||
isVolumeGroupAssociatedToStrategy = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertTrue("Volume Group (" + audioVolumeGroup.toString()
|
||||
+ ") has no associated strategy for stream "
|
||||
+ AudioSystem.streamToString(avgStreamType) + "(" + avgStreamType + ")",
|
||||
isVolumeGroupAssociatedToStrategy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Test Volume per Attributes setter/getters
|
||||
//-----------------------------------------------------------------
|
||||
public void testSetGetVolumePerAttributesWithInvalidAttributes() throws Exception {
|
||||
AudioAttributes nullAttributes = null;
|
||||
|
||||
assertThrows(NullPointerException.class,
|
||||
() -> mAudioManager.getMaxVolumeIndexForAttributes(nullAttributes));
|
||||
|
||||
assertThrows(NullPointerException.class,
|
||||
() -> mAudioManager.getMinVolumeIndexForAttributes(nullAttributes));
|
||||
|
||||
assertThrows(NullPointerException.class,
|
||||
() -> mAudioManager.getVolumeIndexForAttributes(nullAttributes));
|
||||
|
||||
assertThrows(NullPointerException.class,
|
||||
() -> mAudioManager.setVolumeIndexForAttributes(
|
||||
nullAttributes, 0 /*index*/, 0/*flags*/));
|
||||
}
|
||||
|
||||
public void testSetGetVolumePerAttributes() throws Exception {
|
||||
for (int usage : AudioAttributes.SDK_USAGES) {
|
||||
if (usage == AudioAttributes.USAGE_UNKNOWN) {
|
||||
continue;
|
||||
}
|
||||
AudioAttributes aaForUsage = new AudioAttributes.Builder().setUsage(usage).build();
|
||||
int indexMin = 0;
|
||||
int indexMax = 0;
|
||||
int index = 0;
|
||||
Exception ex = null;
|
||||
|
||||
try {
|
||||
indexMax = mAudioManager.getMaxVolumeIndexForAttributes(aaForUsage);
|
||||
} catch (Exception e) {
|
||||
ex = e; // unexpected
|
||||
}
|
||||
assertNull("Exception was thrown for valid attributes", ex);
|
||||
ex = null;
|
||||
try {
|
||||
indexMin = mAudioManager.getMinVolumeIndexForAttributes(aaForUsage);
|
||||
} catch (Exception e) {
|
||||
ex = e; // unexpected
|
||||
}
|
||||
assertNull("Exception was thrown for valid attributes", ex);
|
||||
ex = null;
|
||||
try {
|
||||
index = mAudioManager.getVolumeIndexForAttributes(aaForUsage);
|
||||
} catch (Exception e) {
|
||||
ex = e; // unexpected
|
||||
}
|
||||
assertNull("Exception was thrown for valid attributes", ex);
|
||||
ex = null;
|
||||
try {
|
||||
mAudioManager.setVolumeIndexForAttributes(aaForUsage, indexMin, 0/*flags*/);
|
||||
} catch (Exception e) {
|
||||
ex = e; // unexpected
|
||||
}
|
||||
assertNull("Exception was thrown for valid attributes", ex);
|
||||
|
||||
index = mAudioManager.getVolumeIndexForAttributes(aaForUsage);
|
||||
assertEquals(index, indexMin);
|
||||
|
||||
mAudioManager.setVolumeIndexForAttributes(aaForUsage, indexMax, 0/*flags*/);
|
||||
index = mAudioManager.getVolumeIndexForAttributes(aaForUsage);
|
||||
assertEquals(index, indexMax);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Test register/unregister VolumeGroupCallback
|
||||
//-----------------------------------------------------------------
|
||||
public void testVolumeGroupCallback() throws Exception {
|
||||
List<AudioVolumeGroup> audioVolumeGroups = mAudioManager.getAudioVolumeGroups();
|
||||
assertTrue(audioVolumeGroups.size() > 0);
|
||||
|
||||
AudioVolumeGroupCallbackHelper vgCbReceiver = new AudioVolumeGroupCallbackHelper();
|
||||
mAudioManager.registerVolumeGroupCallback(mContext.getMainExecutor(), vgCbReceiver);
|
||||
|
||||
final List<Integer> publicStreams = Ints.asList(PUBLIC_STREAM_TYPES);
|
||||
try {
|
||||
// Validate Audio Volume Groups callback reception
|
||||
for (final AudioVolumeGroup audioVolumeGroup : audioVolumeGroups) {
|
||||
int volumeGroupId = audioVolumeGroup.getId();
|
||||
|
||||
// Set the receiver to filter only the current group callback
|
||||
vgCbReceiver.setExpectedVolumeGroup(volumeGroupId);
|
||||
|
||||
List<AudioAttributes> avgAttributes = audioVolumeGroup.getAudioAttributes();
|
||||
int[] avgStreamTypes = audioVolumeGroup.getLegacyStreamTypes();
|
||||
|
||||
int index = 0;
|
||||
int indexMax = 0;
|
||||
int indexMin = 0;
|
||||
|
||||
// Set the volume per attributes (if valid) and wait the callback
|
||||
for (final AudioAttributes aa : avgAttributes) {
|
||||
if (aa.equals(sDefaultAttributes)) {
|
||||
// Some volume groups may not have valid attributes, used for internal
|
||||
// volume management like patch/rerouting
|
||||
// so bailing out strategy retrieval from attributes
|
||||
continue;
|
||||
}
|
||||
index = mAudioManager.getVolumeIndexForAttributes(aa);
|
||||
indexMax = mAudioManager.getMaxVolumeIndexForAttributes(aa);
|
||||
indexMin = mAudioManager.getMinVolumeIndexForAttributes(aa);
|
||||
index = incrementVolumeIndex(index, indexMin, indexMax);
|
||||
|
||||
vgCbReceiver.setExpectedVolumeGroup(volumeGroupId);
|
||||
mAudioManager.setVolumeIndexForAttributes(aa, index, 0/*flags*/);
|
||||
assertTrue(vgCbReceiver.waitForExpectedVolumeGroupChanged(
|
||||
AudioVolumeGroupCallbackHelper.ASYNC_TIMEOUT_MS));
|
||||
|
||||
int readIndex = mAudioManager.getVolumeIndexForAttributes(aa);
|
||||
assertEquals(readIndex, index);
|
||||
}
|
||||
// Set the volume per stream type (if valid) and wait the callback
|
||||
for (final int avgStreamType : avgStreamTypes) {
|
||||
if (avgStreamType == AudioSystem.STREAM_DEFAULT) {
|
||||
// Some Volume Groups may not have corresponding stream types as they
|
||||
// intends to address volume setting per attributes to avoid adding new
|
||||
// stream type and going on deprecating the stream type even for volume
|
||||
// so bailing out strategy retrieval from stream type
|
||||
continue;
|
||||
}
|
||||
if (!publicStreams.contains(avgStreamType)
|
||||
|| avgStreamType == AudioManager.STREAM_ACCESSIBILITY) {
|
||||
// Limit scope of test to public stream that do not require any
|
||||
// permission (e.g. Changing ACCESSIBILITY is subject to permission).
|
||||
continue;
|
||||
}
|
||||
index = mAudioManager.getStreamVolume(avgStreamType);
|
||||
indexMax = mAudioManager.getStreamMaxVolume(avgStreamType);
|
||||
indexMin = mAudioManager.getStreamMinVolumeInt(avgStreamType);
|
||||
index = incrementVolumeIndex(index, indexMin, indexMax);
|
||||
|
||||
vgCbReceiver.setExpectedVolumeGroup(volumeGroupId);
|
||||
mAudioManager.setStreamVolume(avgStreamType, index, 0/*flags*/);
|
||||
assertTrue(vgCbReceiver.waitForExpectedVolumeGroupChanged(
|
||||
AudioVolumeGroupCallbackHelper.ASYNC_TIMEOUT_MS));
|
||||
|
||||
int readIndex = mAudioManager.getStreamVolume(avgStreamType);
|
||||
assertEquals(index, readIndex);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
mAudioManager.unregisterVolumeGroupCallback(vgCbReceiver);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.audiopolicytest;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
|
||||
public class AudioPolicyTest extends Activity {
|
||||
|
||||
public AudioPolicyTest() {
|
||||
}
|
||||
|
||||
/** Called when the activity is first created. */
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
setContentView(R.layout.audiopolicytest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
}
|
||||
}
|
@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.audiopolicytest;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
|
||||
import android.media.AudioAttributes;
|
||||
import android.media.AudioSystem;
|
||||
import android.media.audiopolicy.AudioProductStrategy;
|
||||
import android.media.audiopolicy.AudioVolumeGroup;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class AudioProductStrategyTest extends AudioVolumesTestBase {
|
||||
private static final String TAG = "AudioProductStrategyTest";
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Test getAudioProductStrategies and validate strategies
|
||||
//-----------------------------------------------------------------
|
||||
public void testGetProductStrategies() throws Exception {
|
||||
List<AudioProductStrategy> audioProductStrategies =
|
||||
AudioProductStrategy.getAudioProductStrategies();
|
||||
|
||||
assertNotNull(audioProductStrategies);
|
||||
assertTrue(audioProductStrategies.size() > 0);
|
||||
|
||||
for (final AudioProductStrategy aps : audioProductStrategies) {
|
||||
assertTrue(aps.getId() >= 0);
|
||||
|
||||
AudioAttributes aa = aps.getAudioAttributes();
|
||||
assertNotNull(aa);
|
||||
|
||||
// Ensure API consistency
|
||||
assertTrue(aps.supportsAudioAttributes(aa));
|
||||
|
||||
int streamType = aps.getLegacyStreamTypeForAudioAttributes(aa);
|
||||
if (streamType == AudioSystem.STREAM_DEFAULT) {
|
||||
// bailing out test for volume group APIs consistency
|
||||
continue;
|
||||
}
|
||||
final int volumeGroupFromStream = aps.getVolumeGroupIdForLegacyStreamType(streamType);
|
||||
final int volumeGroupFromAttributes = aps.getVolumeGroupIdForAudioAttributes(aa);
|
||||
assertNotEquals(volumeGroupFromStream, AudioVolumeGroup.DEFAULT_VOLUME_GROUP);
|
||||
assertEquals(volumeGroupFromStream, volumeGroupFromAttributes);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Test stream to/from attributes conversion
|
||||
//-----------------------------------------------------------------
|
||||
public void testAudioAttributesFromStreamTypes() throws Exception {
|
||||
List<AudioProductStrategy> audioProductStrategies =
|
||||
AudioProductStrategy.getAudioProductStrategies();
|
||||
|
||||
assertNotNull(audioProductStrategies);
|
||||
assertTrue(audioProductStrategies.size() > 0);
|
||||
|
||||
for (final int streamType : PUBLIC_STREAM_TYPES) {
|
||||
AudioAttributes aaFromStreamType =
|
||||
AudioProductStrategy.getAudioAttributesForStrategyWithLegacyStreamType(
|
||||
streamType);
|
||||
|
||||
// No strategy found for this stream type or no attributes defined for the strategy
|
||||
// hosting this stream type; Bailing out the test, just ensure that any request
|
||||
// for reciproque API with the unknown attributes would return default stream
|
||||
// for volume control, aka STREAM_MUSIC.
|
||||
if (aaFromStreamType.equals(sInvalidAttributes)) {
|
||||
assertEquals(AudioSystem.STREAM_MUSIC,
|
||||
AudioProductStrategy.getLegacyStreamTypeForStrategyWithAudioAttributes(
|
||||
aaFromStreamType));
|
||||
} else {
|
||||
// Attributes are valid, i.e. a strategy was found supporting this stream type
|
||||
// with valid attributes. Ensure reciproque works fine
|
||||
int streamTypeFromAttributes =
|
||||
AudioProductStrategy.getLegacyStreamTypeForStrategyWithAudioAttributes(
|
||||
aaFromStreamType);
|
||||
assertEquals("stream " + AudioSystem.streamToString(streamType) + "("
|
||||
+ streamType + ") expected to match attributes "
|
||||
+ aaFromStreamType.toString() + " got instead stream "
|
||||
+ AudioSystem.streamToString(streamTypeFromAttributes) + "("
|
||||
+ streamTypeFromAttributes + ") expected to match attributes ",
|
||||
streamType, streamTypeFromAttributes);
|
||||
}
|
||||
|
||||
// Now identify the strategy supporting this stream type, ensure uniqueness
|
||||
boolean strategyFound = false;
|
||||
for (final AudioProductStrategy aps : audioProductStrategies) {
|
||||
AudioAttributes aaFromAps =
|
||||
aps.getAudioAttributesForLegacyStreamType(streamType);
|
||||
|
||||
if (aaFromAps == null) {
|
||||
// not this one...
|
||||
continue;
|
||||
}
|
||||
// Got it!
|
||||
assertFalse("Unique ProductStrategy shall match for a given stream type",
|
||||
strategyFound);
|
||||
strategyFound = true;
|
||||
|
||||
// Ensure getters aligned
|
||||
assertEquals(aaFromStreamType, aaFromAps);
|
||||
assertTrue(aps.supportsAudioAttributes(aaFromStreamType));
|
||||
|
||||
// Ensure reciproque works fine
|
||||
assertEquals(streamType,
|
||||
aps.getLegacyStreamTypeForAudioAttributes(aaFromStreamType));
|
||||
|
||||
// Ensure consistency of volume group getter API
|
||||
final int volumeGroupFromStream =
|
||||
aps.getVolumeGroupIdForLegacyStreamType(streamType);
|
||||
final int volumeGroupFromAttributes =
|
||||
aps.getVolumeGroupIdForAudioAttributes(aaFromStreamType);
|
||||
assertNotEquals(volumeGroupFromStream, AudioVolumeGroup.DEFAULT_VOLUME_GROUP);
|
||||
assertEquals(volumeGroupFromStream, volumeGroupFromAttributes);
|
||||
}
|
||||
if (!strategyFound) {
|
||||
// No strategy found, ensure volume control is MUSIC
|
||||
assertEquals(AudioSystem.STREAM_MUSIC,
|
||||
AudioProductStrategy.getLegacyStreamTypeForStrategyWithAudioAttributes(
|
||||
aaFromStreamType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void testAudioAttributesToStreamTypes() throws Exception {
|
||||
List<AudioProductStrategy> audioProductStrategies =
|
||||
AudioProductStrategy.getAudioProductStrategies();
|
||||
|
||||
assertNotNull(audioProductStrategies);
|
||||
assertTrue(audioProductStrategies.size() > 0);
|
||||
|
||||
for (int usage : AudioAttributes.SDK_USAGES) {
|
||||
AudioAttributes aaForUsage = new AudioAttributes.Builder().setUsage(usage).build();
|
||||
|
||||
int streamTypeFromUsage =
|
||||
AudioProductStrategy.getLegacyStreamTypeForStrategyWithAudioAttributes(
|
||||
aaForUsage);
|
||||
|
||||
// Cannot be undefined, always shall fall back on a valid stream type
|
||||
// to be able to control the volume
|
||||
assertNotEquals(streamTypeFromUsage, AudioSystem.STREAM_DEFAULT);
|
||||
|
||||
Log.w(TAG, "GUSTAVE aaForUsage=" + aaForUsage.toString());
|
||||
|
||||
// Now identify the strategy hosting these Audio Attributes and ensure informations
|
||||
// matches.
|
||||
// Now identify the strategy supporting this stream type, ensure uniqueness
|
||||
boolean strategyFound = false;
|
||||
for (final AudioProductStrategy aps : audioProductStrategies) {
|
||||
if (!aps.supportsAudioAttributes(aaForUsage)) {
|
||||
// Not this one
|
||||
continue;
|
||||
}
|
||||
// Got it!
|
||||
String msg = "Unique ProductStrategy shall match for a given audio attributes "
|
||||
+ aaForUsage.toString() + " already associated also matches with"
|
||||
+ aps.toString();
|
||||
assertFalse(msg, strategyFound);
|
||||
strategyFound = true;
|
||||
|
||||
// It may not return the expected stream type if the strategy does not have
|
||||
// associated stream type.
|
||||
// Behavior of member function getLegacyStreamTypeForAudioAttributes is
|
||||
// different than getLegacyStreamTypeForStrategyWithAudioAttributes since it
|
||||
// does not fallback on MUSIC stream type for volume operation
|
||||
int streamTypeFromAps = aps.getLegacyStreamTypeForAudioAttributes(aaForUsage);
|
||||
if (streamTypeFromAps == AudioSystem.STREAM_DEFAULT) {
|
||||
// No stream type assigned to this strategy
|
||||
// Expect static API to return default stream type for volume (aka MUSIC)
|
||||
assertEquals("Strategy (" + aps.toString() + ") has no associated stream "
|
||||
+ ", must fallback on MUSIC stream as default",
|
||||
streamTypeFromUsage, AudioSystem.STREAM_MUSIC);
|
||||
} else {
|
||||
assertEquals("Attributes " + aaForUsage.toString() + " associated to stream "
|
||||
+ AudioSystem.streamToString(streamTypeFromUsage)
|
||||
+ " are supported by strategy (" + aps.toString() + ") which reports "
|
||||
+ " these attributes are associated to stream "
|
||||
+ AudioSystem.streamToString(streamTypeFromAps),
|
||||
streamTypeFromUsage, streamTypeFromAps);
|
||||
|
||||
// Ensure consistency of volume group getter API
|
||||
int volumeGroupFromStream =
|
||||
aps.getVolumeGroupIdForLegacyStreamType(streamTypeFromAps);
|
||||
int volumeGroupFromAttributes =
|
||||
aps.getVolumeGroupIdForAudioAttributes(aaForUsage);
|
||||
assertNotEquals(
|
||||
volumeGroupFromStream, AudioVolumeGroup.DEFAULT_VOLUME_GROUP);
|
||||
assertEquals(volumeGroupFromStream, volumeGroupFromAttributes);
|
||||
}
|
||||
}
|
||||
if (!strategyFound) {
|
||||
// No strategy found for the given attributes, the expected stream must be MUSIC
|
||||
assertEquals(streamTypeFromUsage, AudioSystem.STREAM_MUSIC);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.audiopolicytest;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import android.media.AudioManager;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
||||
final class AudioVolumeGroupCallbackHelper extends AudioManager.VolumeGroupCallback {
|
||||
private static final String TAG = "AudioVolumeGroupCallbackHelper";
|
||||
public static final long ASYNC_TIMEOUT_MS = 800;
|
||||
|
||||
private int mExpectedVolumeGroupId;
|
||||
|
||||
private CountDownLatch mVolumeGroupChanged = null;
|
||||
|
||||
void setExpectedVolumeGroup(int group) {
|
||||
mVolumeGroupChanged = new CountDownLatch(1);
|
||||
mExpectedVolumeGroupId = group;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAudioVolumeGroupChanged(int group, int flags) {
|
||||
if (group != mExpectedVolumeGroupId) {
|
||||
return;
|
||||
}
|
||||
if (mVolumeGroupChanged == null) {
|
||||
Log.wtf(TAG, "Received callback but object not initialized");
|
||||
return;
|
||||
}
|
||||
if (mVolumeGroupChanged.getCount() <= 0) {
|
||||
Log.i(TAG, "callback for group: " + group + " already received");
|
||||
return;
|
||||
}
|
||||
mVolumeGroupChanged.countDown();
|
||||
}
|
||||
|
||||
public boolean waitForExpectedVolumeGroupChanged(long timeOutMs) {
|
||||
assertNotNull("Call first setExpectedVolumeGroup before waiting...", mVolumeGroupChanged);
|
||||
boolean timeoutReached = false;
|
||||
if (mVolumeGroupChanged.getCount() == 0) {
|
||||
// done already...
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
timeoutReached = !mVolumeGroupChanged.await(ASYNC_TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||
} catch (InterruptedException e) { }
|
||||
return !timeoutReached;
|
||||
}
|
||||
}
|
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.audiopolicytest;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertThrows;
|
||||
|
||||
import android.media.AudioAttributes;
|
||||
import android.media.AudioManager;
|
||||
import android.media.audiopolicy.AudioVolumeGroup;
|
||||
import android.media.audiopolicy.AudioVolumeGroupChangeHandler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class AudioVolumeGroupChangeHandlerTest extends AudioVolumesTestBase {
|
||||
private static final String TAG = "AudioVolumeGroupChangeHandlerTest";
|
||||
|
||||
public void testRegisterInvalidCallback() throws Exception {
|
||||
final AudioVolumeGroupChangeHandler audioAudioVolumeGroupChangedHandler =
|
||||
new AudioVolumeGroupChangeHandler();
|
||||
|
||||
audioAudioVolumeGroupChangedHandler.init();
|
||||
|
||||
assertThrows(NullPointerException.class, () -> {
|
||||
AudioManager.VolumeGroupCallback nullCb = null;
|
||||
audioAudioVolumeGroupChangedHandler.registerListener(nullCb);
|
||||
});
|
||||
}
|
||||
|
||||
public void testUnregisterInvalidCallback() throws Exception {
|
||||
final AudioVolumeGroupChangeHandler audioAudioVolumeGroupChangedHandler =
|
||||
new AudioVolumeGroupChangeHandler();
|
||||
|
||||
audioAudioVolumeGroupChangedHandler.init();
|
||||
|
||||
final AudioVolumeGroupCallbackHelper cb = new AudioVolumeGroupCallbackHelper();
|
||||
audioAudioVolumeGroupChangedHandler.registerListener(cb);
|
||||
|
||||
assertThrows(NullPointerException.class, () -> {
|
||||
AudioManager.VolumeGroupCallback nullCb = null;
|
||||
audioAudioVolumeGroupChangedHandler.unregisterListener(nullCb);
|
||||
});
|
||||
audioAudioVolumeGroupChangedHandler.unregisterListener(cb);
|
||||
}
|
||||
|
||||
public void testRegisterUnregisterCallback() throws Exception {
|
||||
final AudioVolumeGroupChangeHandler audioAudioVolumeGroupChangedHandler =
|
||||
new AudioVolumeGroupChangeHandler();
|
||||
|
||||
audioAudioVolumeGroupChangedHandler.init();
|
||||
final AudioVolumeGroupCallbackHelper validCb = new AudioVolumeGroupCallbackHelper();
|
||||
|
||||
// Should not assert, otherwise test will fail
|
||||
audioAudioVolumeGroupChangedHandler.registerListener(validCb);
|
||||
|
||||
// Should not assert, otherwise test will fail
|
||||
audioAudioVolumeGroupChangedHandler.unregisterListener(validCb);
|
||||
}
|
||||
|
||||
public void testCallbackReceived() throws Exception {
|
||||
final AudioVolumeGroupChangeHandler audioAudioVolumeGroupChangedHandler =
|
||||
new AudioVolumeGroupChangeHandler();
|
||||
|
||||
audioAudioVolumeGroupChangedHandler.init();
|
||||
|
||||
final AudioVolumeGroupCallbackHelper validCb = new AudioVolumeGroupCallbackHelper();
|
||||
audioAudioVolumeGroupChangedHandler.registerListener(validCb);
|
||||
|
||||
List<AudioVolumeGroup> audioVolumeGroups = mAudioManager.getAudioVolumeGroups();
|
||||
assertTrue(audioVolumeGroups.size() > 0);
|
||||
|
||||
try {
|
||||
for (final AudioVolumeGroup audioVolumeGroup : audioVolumeGroups) {
|
||||
int volumeGroupId = audioVolumeGroup.getId();
|
||||
|
||||
List<AudioAttributes> avgAttributes = audioVolumeGroup.getAudioAttributes();
|
||||
// Set the volume per attributes (if valid) and wait the callback
|
||||
if (avgAttributes.size() == 0 || avgAttributes.get(0).equals(sDefaultAttributes)) {
|
||||
// Some volume groups may not have valid attributes, used for internal
|
||||
// volume management like patch/rerouting
|
||||
// so bailing out strategy retrieval from attributes
|
||||
continue;
|
||||
}
|
||||
final AudioAttributes aa = avgAttributes.get(0);
|
||||
|
||||
int index = mAudioManager.getVolumeIndexForAttributes(aa);
|
||||
int indexMax = mAudioManager.getMaxVolumeIndexForAttributes(aa);
|
||||
int indexMin = mAudioManager.getMinVolumeIndexForAttributes(aa);
|
||||
|
||||
final int indexForAa = incrementVolumeIndex(index, indexMin, indexMax);
|
||||
|
||||
// Set the receiver to filter only the current group callback
|
||||
validCb.setExpectedVolumeGroup(volumeGroupId);
|
||||
mAudioManager.setVolumeIndexForAttributes(aa, indexForAa, 0/*flags*/);
|
||||
assertTrue(validCb.waitForExpectedVolumeGroupChanged(
|
||||
AudioVolumeGroupCallbackHelper.ASYNC_TIMEOUT_MS));
|
||||
|
||||
final int readIndex = mAudioManager.getVolumeIndexForAttributes(aa);
|
||||
assertEquals(readIndex, indexForAa);
|
||||
}
|
||||
} finally {
|
||||
audioAudioVolumeGroupChangedHandler.unregisterListener(validCb);
|
||||
}
|
||||
}
|
||||
|
||||
public void testMultipleCallbackReceived() throws Exception {
|
||||
|
||||
final AudioVolumeGroupChangeHandler audioAudioVolumeGroupChangedHandler =
|
||||
new AudioVolumeGroupChangeHandler();
|
||||
|
||||
audioAudioVolumeGroupChangedHandler.init();
|
||||
|
||||
final int callbackCount = 10;
|
||||
final List<AudioVolumeGroupCallbackHelper> validCbs =
|
||||
new ArrayList<AudioVolumeGroupCallbackHelper>();
|
||||
for (int i = 0; i < callbackCount; i++) {
|
||||
validCbs.add(new AudioVolumeGroupCallbackHelper());
|
||||
}
|
||||
for (final AudioVolumeGroupCallbackHelper cb : validCbs) {
|
||||
audioAudioVolumeGroupChangedHandler.registerListener(cb);
|
||||
}
|
||||
|
||||
List<AudioVolumeGroup> audioVolumeGroups = mAudioManager.getAudioVolumeGroups();
|
||||
assertTrue(audioVolumeGroups.size() > 0);
|
||||
|
||||
try {
|
||||
for (final AudioVolumeGroup audioVolumeGroup : audioVolumeGroups) {
|
||||
int volumeGroupId = audioVolumeGroup.getId();
|
||||
|
||||
List<AudioAttributes> avgAttributes = audioVolumeGroup.getAudioAttributes();
|
||||
// Set the volume per attributes (if valid) and wait the callback
|
||||
if (avgAttributes.size() == 0 || avgAttributes.get(0).equals(sDefaultAttributes)) {
|
||||
// Some volume groups may not have valid attributes, used for internal
|
||||
// volume management like patch/rerouting
|
||||
// so bailing out strategy retrieval from attributes
|
||||
continue;
|
||||
}
|
||||
AudioAttributes aa = avgAttributes.get(0);
|
||||
|
||||
int index = mAudioManager.getVolumeIndexForAttributes(aa);
|
||||
int indexMax = mAudioManager.getMaxVolumeIndexForAttributes(aa);
|
||||
int indexMin = mAudioManager.getMinVolumeIndexForAttributes(aa);
|
||||
|
||||
final int indexForAa = incrementVolumeIndex(index, indexMin, indexMax);
|
||||
|
||||
// Set the receiver to filter only the current group callback
|
||||
for (final AudioVolumeGroupCallbackHelper cb : validCbs) {
|
||||
cb.setExpectedVolumeGroup(volumeGroupId);
|
||||
}
|
||||
mAudioManager.setVolumeIndexForAttributes(aa, indexForAa, 0/*flags*/);
|
||||
|
||||
for (final AudioVolumeGroupCallbackHelper cb : validCbs) {
|
||||
assertTrue(cb.waitForExpectedVolumeGroupChanged(
|
||||
AudioVolumeGroupCallbackHelper.ASYNC_TIMEOUT_MS));
|
||||
}
|
||||
int readIndex = mAudioManager.getVolumeIndexForAttributes(aa);
|
||||
assertEquals(readIndex, indexForAa);
|
||||
}
|
||||
} finally {
|
||||
for (final AudioVolumeGroupCallbackHelper cb : validCbs) {
|
||||
audioAudioVolumeGroupChangedHandler.unregisterListener(cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.audiopolicytest;
|
||||
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
|
||||
import android.media.AudioAttributes;
|
||||
import android.media.AudioSystem;
|
||||
import android.media.audiopolicy.AudioProductStrategy;
|
||||
import android.media.audiopolicy.AudioVolumeGroup;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class AudioVolumeGroupTest extends AudioVolumesTestBase {
|
||||
private static final String TAG = "AudioVolumeGroupTest";
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Test getAudioVolumeGroups and validate groud id
|
||||
//-----------------------------------------------------------------
|
||||
public void testGetVolumeGroupsFromNonServiceCaller() throws Exception {
|
||||
// The transaction behind getAudioVolumeGroups will fail. Check is done at binder level
|
||||
// with policy service. Error is not reported, the list is just empty.
|
||||
// Request must come from service components
|
||||
List<AudioVolumeGroup> audioVolumeGroup = AudioVolumeGroup.getAudioVolumeGroups();
|
||||
|
||||
assertNotNull(audioVolumeGroup);
|
||||
assertEquals(audioVolumeGroup.size(), 0);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Test getAudioVolumeGroups and validate groud id
|
||||
//-----------------------------------------------------------------
|
||||
public void testGetVolumeGroups() throws Exception {
|
||||
// Through AudioManager, the transaction behind getAudioVolumeGroups will succeed
|
||||
final List<AudioVolumeGroup> audioVolumeGroup = mAudioManager.getAudioVolumeGroups();
|
||||
assertNotNull(audioVolumeGroup);
|
||||
assertTrue(audioVolumeGroup.size() > 0);
|
||||
|
||||
final List<AudioProductStrategy> audioProductStrategies =
|
||||
mAudioManager.getAudioProductStrategies();
|
||||
assertTrue(audioProductStrategies.size() > 0);
|
||||
|
||||
for (final AudioVolumeGroup avg : audioVolumeGroup) {
|
||||
int avgId = avg.getId();
|
||||
assertNotEquals(avgId, AudioVolumeGroup.DEFAULT_VOLUME_GROUP);
|
||||
|
||||
List<AudioAttributes> avgAttributes = avg.getAudioAttributes();
|
||||
assertNotNull(avgAttributes);
|
||||
|
||||
final int[] avgStreamTypes = avg.getLegacyStreamTypes();
|
||||
assertNotNull(avgStreamTypes);
|
||||
|
||||
// for each volume group attributes, find the matching product strategy and ensure
|
||||
// it is linked the considered volume group
|
||||
for (final AudioAttributes aa : avgAttributes) {
|
||||
if (aa.equals(sDefaultAttributes)) {
|
||||
// Some volume groups may not have valid attributes, used for internal
|
||||
// volume management like patch/rerouting
|
||||
// so bailing out strategy retrieval from attributes
|
||||
continue;
|
||||
}
|
||||
boolean isVolumeGroupAssociatedToStrategy = false;
|
||||
for (final AudioProductStrategy aps : audioProductStrategies) {
|
||||
int groupId = aps.getVolumeGroupIdForAudioAttributes(aa);
|
||||
if (groupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) {
|
||||
// Note that Audio Product Strategies are priority ordered, and the
|
||||
// the first one matching the AudioAttributes will be used to identify
|
||||
// the volume group associated to the request.
|
||||
assertTrue(aps.supportsAudioAttributes(aa));
|
||||
assertEquals("Volume Group ID (" + avg.toString()
|
||||
+ "), and Volume group ID associated to Strategy ("
|
||||
+ aps.toString() + ") both supporting attributes "
|
||||
+ aa.toString() + " are mismatching",
|
||||
avgId, groupId);
|
||||
isVolumeGroupAssociatedToStrategy = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertTrue("Volume Group (" + avg.toString()
|
||||
+ ") has no associated strategy for attributes " + aa.toString(),
|
||||
isVolumeGroupAssociatedToStrategy);
|
||||
}
|
||||
|
||||
// for each volume group stream type, find the matching product strategy and ensure
|
||||
// it is linked the considered volume group
|
||||
for (final int avgStreamType : avgStreamTypes) {
|
||||
if (avgStreamType == AudioSystem.STREAM_DEFAULT) {
|
||||
// Some Volume Groups may not have corresponding stream types as they
|
||||
// intends to address volume setting per attributes to avoid adding new
|
||||
// stream type and going on deprecating the stream type even for volume
|
||||
// so bailing out strategy retrieval from stream type
|
||||
continue;
|
||||
}
|
||||
boolean isVolumeGroupAssociatedToStrategy = false;
|
||||
for (final AudioProductStrategy aps : audioProductStrategies) {
|
||||
int groupId = aps.getVolumeGroupIdForLegacyStreamType(avgStreamType);
|
||||
if (groupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP) {
|
||||
|
||||
assertEquals("Volume Group ID (" + avg.toString()
|
||||
+ "), and Volume group ID associated to Strategy ("
|
||||
+ aps.toString() + ") both supporting stream "
|
||||
+ AudioSystem.streamToString(avgStreamType) + "("
|
||||
+ avgStreamType + ") are mismatching",
|
||||
avgId, groupId);
|
||||
|
||||
isVolumeGroupAssociatedToStrategy = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertTrue("Volume Group (" + avg.toString()
|
||||
+ ") has no associated strategy for stream "
|
||||
+ AudioSystem.streamToString(avgStreamType) + "(" + avgStreamType + ")",
|
||||
isVolumeGroupAssociatedToStrategy);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.audiopolicytest;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.media.AudioAttributes;
|
||||
import android.media.AudioManager;
|
||||
import android.media.audiopolicy.AudioProductStrategy;
|
||||
import android.media.audiopolicy.AudioVolumeGroup;
|
||||
import android.test.ActivityInstrumentationTestCase2;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class AudioVolumesTestBase extends ActivityInstrumentationTestCase2<AudioPolicyTest> {
|
||||
public AudioManager mAudioManager;
|
||||
Context mContext;
|
||||
private Map<Integer, Integer> mOriginalStreamVolumes = new HashMap<>();
|
||||
private Map<Integer, Integer> 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Note: must be called with shell permission (MODIFY_AUDIO_ROUTING)
|
||||
*/
|
||||
private void storeAllVolumes() {
|
||||
List<AudioVolumeGroup> 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));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Note: must be called with shell permission (MODIFY_AUDIO_ROUTING)
|
||||
*/
|
||||
private void restoreAllVolumes() {
|
||||
List<AudioVolumeGroup> audioVolumeGroups = mAudioManager.getAudioVolumeGroups();
|
||||
for (Map.Entry<Integer, Integer> 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<Integer, Integer> 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;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user