blob: 044217300e1625ad169aaab9678feec70c6ffd19 [file] [log] [blame]
/*
* Copyright (C) 2023 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.car.audio;
import static android.car.media.CarVolumeGroupEvent.EVENT_TYPE_ATTENUATION_CHANGED;
import static android.car.media.CarVolumeGroupEvent.EVENT_TYPE_MUTE_CHANGED;
import static android.media.AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
import static android.media.AudioAttributes.USAGE_ASSISTANT;
import static android.media.AudioAttributes.USAGE_MEDIA;
import static com.android.car.audio.CarAudioContext.AudioContext;
import static org.junit.Assert.assertThrows;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.car.media.CarAudioManager;
import android.car.media.CarAudioZoneConfigInfo;
import android.car.media.CarVolumeGroupEvent;
import android.car.media.CarVolumeGroupInfo;
import android.car.test.AbstractExpectableTestCase;
import android.hardware.automotive.audiocontrol.AudioGainConfigInfo;
import android.hardware.automotive.audiocontrol.Reasons;
import android.media.AudioAttributes;
import android.media.AudioDeviceAttributes;
import android.media.AudioDeviceInfo;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.List;
@RunWith(MockitoJUnitRunner.class)
public final class CarAudioZoneConfigUnitTest extends AbstractExpectableTestCase {
private static final String MUSIC_ADDRESS = "bus0_music";
private static final String NAV_ADDRESS = "bus1_nav";
private static final String VOICE_ADDRESS = "bus3_voice";
private static final int TEST_ZONE_CONFIG_ID = 1;
private static final String TEST_ZONE_CONFIG_NAME = "Config 0";
private static final String TEST_MUSIC_GROUP_NAME = "Music group name";
private static final String TEST_NAV_GROUP_NAME = "Nav group name";
private static final String TEST_VOICE_GROUP_NAME = "Voice group name";
private static final int TEST_ZONE_ID = 0;
private static final int TEST_MUSIC_GROUP_ID = 0;
private static final int TEST_NAV_GROUP_ID = 20;
private static final int TEST_VOICE_GROUP_ID = 30;
private static final AudioAttributes TEST_MEDIA_ATTRIBUTE =
CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA);
private static final AudioAttributes TEST_ASSISTANT_ATTRIBUTE =
CarAudioContext.getAudioAttributeFromUsage(USAGE_ASSISTANT);
private static final AudioAttributes TEST_NAVIGATION_ATTRIBUTE =
CarAudioContext.getAudioAttributeFromUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE);
private static final CarAudioContext TEST_CAR_AUDIO_CONTEXT = new CarAudioContext(
CarAudioContext.getAllContextsInfo(), /* useCoreAudioRouting= */ false);
@AudioContext
private static final int TEST_MEDIA_CONTEXT =
TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_MEDIA_ATTRIBUTE);
@AudioContext
private static final int TEST_ASSISTANT_CONTEXT =
TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_ASSISTANT_ATTRIBUTE);
@AudioContext
private static final int TEST_NAVIGATION_CONTEXT =
TEST_CAR_AUDIO_CONTEXT.getContextForAudioAttribute(TEST_NAVIGATION_ATTRIBUTE);
@Mock
private CarVolumeGroup mMockMusicGroup;
@Mock
private CarVolumeGroup mMockNavGroup;
@Mock
private CarVolumeGroup mMockVoiceGroup;
private CarAudioZoneConfig.Builder mTestAudioZoneConfigBuilder;
@Before
public void setUp() {
mTestAudioZoneConfigBuilder = new CarAudioZoneConfig.Builder(TEST_ZONE_CONFIG_NAME,
CarAudioManager.PRIMARY_AUDIO_ZONE, TEST_ZONE_CONFIG_ID, /* isDefault= */ true);
mMockMusicGroup = new VolumeGroupBuilder().setName(TEST_MUSIC_GROUP_NAME)
.addDeviceAddressAndContexts(TEST_MEDIA_CONTEXT, MUSIC_ADDRESS)
.setZoneId(TEST_ZONE_ID).setGroupId(TEST_MUSIC_GROUP_ID).build();
mMockNavGroup = new VolumeGroupBuilder().setName(TEST_NAV_GROUP_NAME)
.addDeviceAddressAndContexts(TEST_NAVIGATION_CONTEXT, NAV_ADDRESS)
.setZoneId(TEST_ZONE_ID).setGroupId(TEST_NAV_GROUP_ID).build();
mMockVoiceGroup = new VolumeGroupBuilder().setName(TEST_VOICE_GROUP_NAME)
.addDeviceAddressAndContexts(TEST_ASSISTANT_CONTEXT, VOICE_ADDRESS)
.setZoneId(TEST_ZONE_ID).setGroupId(TEST_VOICE_GROUP_ID).build();
}
@Test
public void getZoneId_fromBuilder() {
expectWithMessage("Builder zone id").that(mTestAudioZoneConfigBuilder.getZoneId())
.isEqualTo(CarAudioManager.PRIMARY_AUDIO_ZONE);
}
@Test
public void getZoneConfigId_fromBuilder() {
expectWithMessage("Builder zone configuration id")
.that(mTestAudioZoneConfigBuilder.getZoneConfigId()).isEqualTo(TEST_ZONE_CONFIG_ID);
}
@Test
public void getZoneId() {
CarAudioZoneConfig zoneConfig = mTestAudioZoneConfigBuilder.build();
expectWithMessage("Zone id")
.that(zoneConfig.getZoneId()).isEqualTo(CarAudioManager.PRIMARY_AUDIO_ZONE);
}
@Test
public void getZoneConfigId() {
CarAudioZoneConfig zoneConfig = mTestAudioZoneConfigBuilder.build();
expectWithMessage("Zone configuration id")
.that(zoneConfig.getZoneConfigId()).isEqualTo(TEST_ZONE_CONFIG_ID);
}
@Test
public void getName() {
CarAudioZoneConfig zoneConfig = mTestAudioZoneConfigBuilder.build();
expectWithMessage("Zone config name")
.that(zoneConfig.getName()).isEqualTo(TEST_ZONE_CONFIG_NAME);
}
@Test
public void getVolumeGroup_withName() {
CarAudioZoneConfig zoneConfig = mTestAudioZoneConfigBuilder.addVolumeGroup(mMockMusicGroup)
.addVolumeGroup(mMockNavGroup).addVolumeGroup(mMockVoiceGroup).build();
expectWithMessage("Volume group with name %s", TEST_MUSIC_GROUP_NAME)
.that(zoneConfig.getVolumeGroup(TEST_MUSIC_GROUP_NAME)).isEqualTo(mMockMusicGroup);
}
@Test
public void getVolumeGroup_withNameNotFound_returnsNull() {
CarAudioZoneConfig zoneConfig = mTestAudioZoneConfigBuilder.addVolumeGroup(mMockMusicGroup)
.addVolumeGroup(mMockNavGroup).addVolumeGroup(mMockVoiceGroup).build();
expectWithMessage("Volume group with name not found")
.that(zoneConfig.getVolumeGroup("Invalid volume group name")).isNull();
}
@Test
public void getVolumeGroup_withGroupId() {
CarAudioZoneConfig zoneConfig = mTestAudioZoneConfigBuilder.addVolumeGroup(mMockMusicGroup)
.addVolumeGroup(mMockNavGroup).addVolumeGroup(mMockVoiceGroup).build();
int groupId = 2;
expectWithMessage("Volume group with id %s", groupId)
.that(zoneConfig.getVolumeGroup(groupId)).isEqualTo(mMockVoiceGroup);
}
@Test
public void getVolumeGroup_withGroupIdOutOfRange() {
CarAudioZoneConfig zoneConfig = mTestAudioZoneConfigBuilder.addVolumeGroup(mMockMusicGroup)
.addVolumeGroup(mMockNavGroup).addVolumeGroup(mMockVoiceGroup).build();
int indexOutOfRange = 4;
IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
() -> zoneConfig.getVolumeGroup(indexOutOfRange));
expectWithMessage("Invalid volume group id exception").that(thrown).hasMessageThat()
.contains("is out of range");
}
@Test
public void isDefault_forDefaultConfig_returnsTrue() {
CarAudioZoneConfig zoneConfig = mTestAudioZoneConfigBuilder.build();
expectWithMessage("Default zone configuration").that(zoneConfig.isDefault()).isTrue();
}
@Test
public void isDefault_forNonDefaultConfig_returnsFalse() {
CarAudioZoneConfig zoneConfig = new CarAudioZoneConfig.Builder(TEST_ZONE_CONFIG_NAME,
CarAudioManager.PRIMARY_AUDIO_ZONE, TEST_ZONE_CONFIG_ID, /* isDefault= */ false)
.build();
expectWithMessage("Non-default zone configuration").that(zoneConfig.isDefault()).isFalse();
}
@Test
public void getVolumeGroupCount() {
CarAudioZoneConfig zoneConfig = mTestAudioZoneConfigBuilder.addVolumeGroup(mMockMusicGroup)
.addVolumeGroup(mMockNavGroup).addVolumeGroup(mMockVoiceGroup).build();
expectWithMessage("Volume group count")
.that(zoneConfig.getVolumeGroupCount()).isEqualTo(3);
}
@Test
public void getCarVolumeGroups() {
CarAudioZoneConfig zoneConfig = mTestAudioZoneConfigBuilder.addVolumeGroup(mMockMusicGroup)
.addVolumeGroup(mMockNavGroup).addVolumeGroup(mMockVoiceGroup).build();
CarVolumeGroup[] volumeGroups = zoneConfig.getVolumeGroups();
expectWithMessage("Car volume groups").that(volumeGroups).asList()
.containsExactly(mMockMusicGroup, mMockNavGroup, mMockVoiceGroup).inOrder();
}
@Test
public void synchronizeCurrentGainIndex() {
int musicGroupGainIndex = 1;
int navGroupGainIndex = 1;
when(mMockMusicGroup.getCurrentGainIndex()).thenReturn(musicGroupGainIndex);
when(mMockNavGroup.getCurrentGainIndex()).thenReturn(navGroupGainIndex);
CarAudioZoneConfig zoneConfig = mTestAudioZoneConfigBuilder.addVolumeGroup(mMockMusicGroup)
.addVolumeGroup(mMockNavGroup).build();
zoneConfig.synchronizeCurrentGainIndex();
verify(mMockMusicGroup).setCurrentGainIndex(musicGroupGainIndex);
verify(mMockNavGroup).setCurrentGainIndex(navGroupGainIndex);
}
@Test
public void updateVolumeGroupsSettingsForUser() {
CarAudioZoneConfig zoneConfig = mTestAudioZoneConfigBuilder.addVolumeGroup(mMockMusicGroup)
.addVolumeGroup(mMockNavGroup).build();
int userId = 11;
zoneConfig.updateVolumeGroupsSettingsForUser(userId);
verify(mMockMusicGroup).loadVolumesSettingsForUser(userId);
verify(mMockNavGroup).loadVolumesSettingsForUser(userId);
}
@Test
public void validateCanUseDynamicMixRouting_addressSharedAmongGroups_forbidUseDynamicRouting() {
CarAudioDeviceInfo musicCarAudioDeviceInfo = Mockito.mock(CarAudioDeviceInfo.class);
CarVolumeGroup mockMusicGroup = new VolumeGroupBuilder()
.addDeviceAddressAndContexts(TEST_MEDIA_CONTEXT, MUSIC_ADDRESS)
.addCarAudioDeviceInfoMock(musicCarAudioDeviceInfo).build();
CarVolumeGroup mockNavGroupRoutingOnMusic = new VolumeGroupBuilder()
.addDeviceAddressAndContexts(TEST_NAVIGATION_CONTEXT, MUSIC_ADDRESS)
.addCarAudioDeviceInfoMock(musicCarAudioDeviceInfo).build();
CarAudioZoneConfig zoneConfig = buildZoneConfig(
List.of(mockMusicGroup, mockNavGroupRoutingOnMusic));
expectWithMessage("Zone configuration does not validate when not using core routing "
+ "and usage is shared among context")
.that(zoneConfig.validateCanUseDynamicMixRouting(/* useCoreAudioRouting= */ false))
.isFalse();
}
@Test
public void validateCanUseDynamicMixRouting_whenUseCoreRouting_disablesDynamicRouting() {
CarAudioDeviceInfo musicCarAudioDeviceInfo = Mockito.mock(CarAudioDeviceInfo.class);
CarVolumeGroup mockMusicGroup = new VolumeGroupBuilder()
.addDeviceAddressAndContexts(TEST_MEDIA_CONTEXT, MUSIC_ADDRESS)
.addCarAudioDeviceInfoMock(musicCarAudioDeviceInfo).build();
CarVolumeGroup mockNavGroupRoutingOnMusic = new VolumeGroupBuilder()
.addDeviceAddressAndContexts(TEST_NAVIGATION_CONTEXT, MUSIC_ADDRESS)
.addCarAudioDeviceInfoMock(musicCarAudioDeviceInfo).build();
CarAudioZoneConfig zoneConfig = buildZoneConfig(
List.of(mockMusicGroup, mockNavGroupRoutingOnMusic));
expectWithMessage("Zone configuration validates when using core routing and addresses "
+ "shared among volume groups")
.that(zoneConfig.validateCanUseDynamicMixRouting(/* useCoreAudioRouting= */ true))
.isTrue();
verify(musicCarAudioDeviceInfo, times(2)).resetCanBeRoutedWithDynamicPolicyMix();
}
@Test
public void validateZoneWhenUsageSharedAmongContext_forbidUseDynamicRouting() {
CarAudioDeviceInfo musicCarAudioDeviceInfo = Mockito.mock(CarAudioDeviceInfo.class);
CarAudioDeviceInfo navCarAudioDeviceInfo = Mockito.mock(CarAudioDeviceInfo.class);
when(musicCarAudioDeviceInfo.getAddress()).thenReturn(MUSIC_ADDRESS);
when(navCarAudioDeviceInfo.getAddress()).thenReturn(NAV_ADDRESS);
CarVolumeGroup mockMusicGroup = new VolumeGroupBuilder()
.addDeviceAddressAndContexts(TEST_MEDIA_CONTEXT, MUSIC_ADDRESS)
.addDeviceAddressAndUsages(USAGE_MEDIA, MUSIC_ADDRESS)
.addCarAudioDeviceInfoMock(musicCarAudioDeviceInfo).build();
CarVolumeGroup mockNavGroupRoutingOnMusic = new VolumeGroupBuilder()
.addDeviceAddressAndContexts(TEST_MEDIA_CONTEXT, NAV_ADDRESS)
.addDeviceAddressAndUsages(USAGE_MEDIA, NAV_ADDRESS)
.addCarAudioDeviceInfoMock(navCarAudioDeviceInfo).build();
CarAudioZoneConfig zoneConfig = buildZoneConfig(
List.of(mockMusicGroup, mockNavGroupRoutingOnMusic));
expectWithMessage("Zone configuration does not validate when not using core routing and "
+ "usage is shared among context")
.that(zoneConfig.validateCanUseDynamicMixRouting(/* useCoreAudioRouting= */ false))
.isFalse();
}
@Test
public void validateZoneWhenUsageSharedAmongContext_usingCoreRouting_disablesDynamicRouting() {
CarAudioDeviceInfo musicCarAudioDeviceInfo = Mockito.mock(CarAudioDeviceInfo.class);
CarAudioDeviceInfo navCarAudioDeviceInfo = Mockito.mock(CarAudioDeviceInfo.class);
when(musicCarAudioDeviceInfo.getAddress()).thenReturn(MUSIC_ADDRESS);
when(navCarAudioDeviceInfo.getAddress()).thenReturn(NAV_ADDRESS);
CarVolumeGroup mockMusicGroup = new VolumeGroupBuilder()
.addDeviceAddressAndContexts(TEST_MEDIA_CONTEXT, MUSIC_ADDRESS)
.addDeviceAddressAndUsages(USAGE_MEDIA, MUSIC_ADDRESS)
.addCarAudioDeviceInfoMock(musicCarAudioDeviceInfo).build();
CarVolumeGroup mockNavGroupRoutingOnMusic = new VolumeGroupBuilder()
.addDeviceAddressAndContexts(TEST_MEDIA_CONTEXT, NAV_ADDRESS)
.addDeviceAddressAndUsages(USAGE_MEDIA, NAV_ADDRESS)
.addCarAudioDeviceInfoMock(navCarAudioDeviceInfo).build();
CarAudioZoneConfig zoneConfig = buildZoneConfig(
List.of(mockMusicGroup, mockNavGroupRoutingOnMusic));
expectWithMessage("Zone configuration validates when using core routing and usage is "
+ "shared among context")
.that(zoneConfig.validateCanUseDynamicMixRouting(/* useCoreAudioRouting= */ true))
.isTrue();
verify(musicCarAudioDeviceInfo, times(2)).resetCanBeRoutedWithDynamicPolicyMix();
verify(navCarAudioDeviceInfo).resetCanBeRoutedWithDynamicPolicyMix();
}
@Test
public void validateZoneWhenUsageSharedAmongContext_notUsingCoreRouting_fails() {
CarAudioDeviceInfo musicCarAudioDeviceInfo = Mockito.mock(CarAudioDeviceInfo.class);
CarAudioDeviceInfo navCarAudioDeviceInfo = Mockito.mock(CarAudioDeviceInfo.class);
when(musicCarAudioDeviceInfo.getAddress()).thenReturn(MUSIC_ADDRESS);
when(navCarAudioDeviceInfo.getAddress()).thenReturn(NAV_ADDRESS);
CarVolumeGroup mockMusicGroup = new VolumeGroupBuilder()
.addDeviceAddressAndContexts(TEST_MEDIA_CONTEXT, MUSIC_ADDRESS)
.addDeviceAddressAndUsages(USAGE_MEDIA, MUSIC_ADDRESS)
.addCarAudioDeviceInfoMock(musicCarAudioDeviceInfo).build();
CarVolumeGroup mockNavGroupRoutingOnMusic = new VolumeGroupBuilder()
.addDeviceAddressAndContexts(TEST_MEDIA_CONTEXT, NAV_ADDRESS)
.addDeviceAddressAndUsages(USAGE_MEDIA, NAV_ADDRESS)
.addCarAudioDeviceInfoMock(navCarAudioDeviceInfo).build();
CarAudioZoneConfig zoneConfig = buildZoneConfig(
List.of(mockMusicGroup, mockNavGroupRoutingOnMusic));
expectWithMessage("Zone configuration does not validate when not using core routing and "
+ "usage is shared among contexts")
.that(zoneConfig.validateCanUseDynamicMixRouting(/* useCoreAudioRouting= */ false))
.isFalse();
verify(musicCarAudioDeviceInfo, never()).resetCanBeRoutedWithDynamicPolicyMix();
verify(navCarAudioDeviceInfo, never()).resetCanBeRoutedWithDynamicPolicyMix();
}
@Test
public void validateVolumeGroups_notUsingCoreAudioRouting_succeeds() {
CarVolumeGroup mockMusicGroup = new VolumeGroupBuilder()
.addDeviceAddressAndContexts(TEST_MEDIA_CONTEXT, MUSIC_ADDRESS).build();
CarVolumeGroup mockNavGroupRoutingOnMusic = new VolumeGroupBuilder()
.addDeviceAddressAndContexts(TEST_NAVIGATION_CONTEXT, NAV_ADDRESS).build();
CarVolumeGroup mockAllOtherContextsGroup = mockContextsExceptMediaAndNavigation();
CarAudioZoneConfig zoneConfig = buildZoneConfig(
List.of(mockMusicGroup, mockNavGroupRoutingOnMusic, mockAllOtherContextsGroup));
expectWithMessage("Volume group validates when not using core audio routing")
.that(zoneConfig.validateVolumeGroups(TEST_CAR_AUDIO_CONTEXT,
/* useCoreAudioRouting= */ false)).isTrue();
}
@Test
public void validateVolumeGroups_usingCoreAudioRouting_succeeds() {
CarVolumeGroup mockMusicGroup = new VolumeGroupBuilder()
.addDeviceAddressAndContexts(TEST_MEDIA_CONTEXT, MUSIC_ADDRESS).build();
CarVolumeGroup mockNavGroupRoutingOnMusic = new VolumeGroupBuilder()
.addDeviceAddressAndContexts(TEST_NAVIGATION_CONTEXT, NAV_ADDRESS).build();
CarVolumeGroup mockAllOtherContextsGroup = mockContextsExceptMediaAndNavigation();
CarAudioZoneConfig zoneConfig = buildZoneConfig(
List.of(mockMusicGroup, mockNavGroupRoutingOnMusic, mockAllOtherContextsGroup));
expectWithMessage("Volume group validates when using core audio routing")
.that(zoneConfig.validateVolumeGroups(TEST_CAR_AUDIO_CONTEXT,
/* useCoreAudioRouting= */ true)).isTrue();
}
@Test
public void validateZoneConfigs_withAddressSharedAmongGroupNotUsingCoreAudioRouting_fails() {
CarVolumeGroup mockMusicGroup = new VolumeGroupBuilder()
.addDeviceAddressAndContexts(TEST_MEDIA_CONTEXT, MUSIC_ADDRESS).build();
CarVolumeGroup mockNavGroupRoutingOnMusic = new VolumeGroupBuilder()
.addDeviceAddressAndContexts(TEST_NAVIGATION_CONTEXT, MUSIC_ADDRESS).build();
CarVolumeGroup mockAllOtherContextsGroup = mockContextsExceptMediaAndNavigation();
CarAudioZoneConfig zoneConfig = buildZoneConfig(
List.of(mockMusicGroup, mockNavGroupRoutingOnMusic, mockAllOtherContextsGroup));
expectWithMessage("Volume group does not validate when not using core audio routing")
.that(zoneConfig.validateVolumeGroups(TEST_CAR_AUDIO_CONTEXT,
/* useCoreAudioRouting= */ false)).isFalse();
}
@Test
public void validateZoneConfigs_withAddressSharedAmongGroupUsingCoreAudioRouting_succeeds() {
CarVolumeGroup mockMusicGroup = new VolumeGroupBuilder()
.addDeviceAddressAndContexts(TEST_MEDIA_CONTEXT, MUSIC_ADDRESS).build();
CarVolumeGroup mockNavGroupRoutingOnMusic = new VolumeGroupBuilder()
.addDeviceAddressAndContexts(TEST_NAVIGATION_CONTEXT, MUSIC_ADDRESS).build();
CarVolumeGroup mockAllOtherContextsGroup = mockContextsExceptMediaAndNavigation();
CarAudioZoneConfig zoneConfig = buildZoneConfig(
List.of(mockMusicGroup, mockNavGroupRoutingOnMusic, mockAllOtherContextsGroup));
expectWithMessage("Volume group validates when using core audio routing")
.that(zoneConfig.validateVolumeGroups(TEST_CAR_AUDIO_CONTEXT,
/* useCoreAudioRouting= */ true)).isTrue();
}
@Test
public void getAudioDeviceInfos() {
AudioDeviceInfo musicAudioDeviceInfo = Mockito.mock(AudioDeviceInfo.class);
AudioDeviceAttributes musicDeviceAttributes =
new AudioDeviceAttributes(musicAudioDeviceInfo);
AudioDeviceInfo navAudioDeviceInfo = Mockito.mock(AudioDeviceInfo.class);
AudioDeviceAttributes navDeviceAttributes =
new AudioDeviceAttributes(navAudioDeviceInfo);
CarAudioDeviceInfo musicCarAudioDeviceInfo = Mockito.mock(CarAudioDeviceInfo.class);
CarAudioDeviceInfo navCarAudioDeviceInfo = Mockito.mock(CarAudioDeviceInfo.class);
when(musicCarAudioDeviceInfo.getAddress()).thenReturn(MUSIC_ADDRESS);
when(navCarAudioDeviceInfo.getAddress()).thenReturn(NAV_ADDRESS);
when(musicCarAudioDeviceInfo.getAudioDevice()).thenReturn(musicDeviceAttributes);
when(navCarAudioDeviceInfo.getAudioDevice()).thenReturn(navDeviceAttributes);
when(navCarAudioDeviceInfo.canBeRoutedWithDynamicPolicyMix()).thenReturn(false);
when(musicCarAudioDeviceInfo.canBeRoutedWithDynamicPolicyMix()).thenReturn(true);
CarVolumeGroup mockMusicGroup = new VolumeGroupBuilder()
.addDeviceAddressAndContexts(TEST_MEDIA_CONTEXT, MUSIC_ADDRESS)
.addCarAudioDeviceInfoMock(musicCarAudioDeviceInfo).build();
CarVolumeGroup mockNavGroupRoutingOnMusic = new VolumeGroupBuilder()
.addDeviceAddressAndContexts(TEST_MEDIA_CONTEXT, NAV_ADDRESS)
.addCarAudioDeviceInfoMock(navCarAudioDeviceInfo).build();
CarAudioZoneConfig zoneConfig = buildZoneConfig(
List.of(mockMusicGroup, mockNavGroupRoutingOnMusic));
expectWithMessage("Zone configuration groups devices")
.that(zoneConfig.getAudioDevice())
.containsExactlyElementsIn(List.of(musicDeviceAttributes, navDeviceAttributes));
}
@Test
public void isAudioDeviceInfoValidForZone_withNullAudioDeviceInfo_returnsFalse() {
CarAudioZoneConfig zoneConfig = mTestAudioZoneConfigBuilder
.addVolumeGroup(mMockMusicGroup).build();
expectWithMessage("Null audio device info")
.that(zoneConfig.isAudioDeviceInfoValidForZone(null)).isFalse();
}
@Test
public void isAudioDeviceInfoValidForZone_withNullDeviceAddress_returnsFalse() {
CarAudioZoneConfig zoneConfig = mTestAudioZoneConfigBuilder
.addVolumeGroup(mMockMusicGroup).build();
AudioDeviceInfo nullAddressDeviceInfo = Mockito.mock(AudioDeviceInfo.class);
when(nullAddressDeviceInfo.getAddress()).thenReturn(null);
expectWithMessage("Invalid audio device info").that(
zoneConfig.isAudioDeviceInfoValidForZone(nullAddressDeviceInfo)).isFalse();
}
@Test
public void isAudioDeviceInfoValidForZone_withEmptyDeviceAddress_returnsFalse() {
CarAudioZoneConfig zoneConfig = mTestAudioZoneConfigBuilder
.addVolumeGroup(mMockMusicGroup).build();
AudioDeviceInfo nullAddressDeviceInfo = Mockito.mock(AudioDeviceInfo.class);
when(nullAddressDeviceInfo.getAddress()).thenReturn("");
expectWithMessage("Device info with invalid address").that(
zoneConfig.isAudioDeviceInfoValidForZone(nullAddressDeviceInfo)).isFalse();
}
@Test
public void isAudioDeviceInfoValidForZone_withDeviceAddressNotInZone_returnsFalse() {
CarAudioZoneConfig zoneConfig = mTestAudioZoneConfigBuilder
.addVolumeGroup(mMockMusicGroup).build();
AudioDeviceInfo nullAddressDeviceInfo = Mockito.mock(AudioDeviceInfo.class);
when(nullAddressDeviceInfo.getAddress()).thenReturn(VOICE_ADDRESS);
expectWithMessage("Non zone audio device info").that(
zoneConfig.isAudioDeviceInfoValidForZone(nullAddressDeviceInfo)).isFalse();
}
@Test
public void isAudioDeviceInfoValidForZone_withDeviceAddressInZone_returnsTrue() {
CarAudioZoneConfig zoneConfig = mTestAudioZoneConfigBuilder
.addVolumeGroup(mMockMusicGroup).build();
AudioDeviceInfo nullAddressDeviceInfo = Mockito.mock(AudioDeviceInfo.class);
when(nullAddressDeviceInfo.getAddress()).thenReturn(MUSIC_ADDRESS);
expectWithMessage("Valid audio device info").that(
zoneConfig.isAudioDeviceInfoValidForZone(nullAddressDeviceInfo)).isTrue();
}
@Test
public void getAudioDeviceInfosSupportingDynamicMix() {
AudioDeviceInfo musicAudioDeviceInfo = Mockito.mock(AudioDeviceInfo.class);
AudioDeviceAttributes musicDeviceAttributes =
new AudioDeviceAttributes(musicAudioDeviceInfo);
CarAudioDeviceInfo musicCarAudioDeviceInfo = Mockito.mock(CarAudioDeviceInfo.class);
CarAudioDeviceInfo navCarAudioDeviceInfo = Mockito.mock(CarAudioDeviceInfo.class);
when(musicCarAudioDeviceInfo.getAddress()).thenReturn(MUSIC_ADDRESS);
when(navCarAudioDeviceInfo.getAddress()).thenReturn(NAV_ADDRESS);
when(musicCarAudioDeviceInfo.getAudioDevice()).thenReturn(musicDeviceAttributes);
when(navCarAudioDeviceInfo.canBeRoutedWithDynamicPolicyMix()).thenReturn(false);
when(musicCarAudioDeviceInfo.canBeRoutedWithDynamicPolicyMix()).thenReturn(true);
CarVolumeGroup mockMusicGroup = new VolumeGroupBuilder()
.addDeviceAddressAndContexts(TEST_MEDIA_CONTEXT, MUSIC_ADDRESS)
.addCarAudioDeviceInfoMock(musicCarAudioDeviceInfo).build();
CarVolumeGroup mockNavGroupRoutingOnMusic = new VolumeGroupBuilder()
.addDeviceAddressAndContexts(TEST_MEDIA_CONTEXT, NAV_ADDRESS)
.addCarAudioDeviceInfoMock(navCarAudioDeviceInfo).build();
CarAudioZoneConfig zoneConfig = buildZoneConfig(
List.of(mockMusicGroup, mockNavGroupRoutingOnMusic));
expectWithMessage("Dynamic mix ready devices")
.that(zoneConfig.getAudioDeviceSupportingDynamicMix())
.containsExactly(musicDeviceAttributes);
}
@Test
public void onAudioGainChanged_withDeviceAddressesInZone() {
CarAudioZoneConfig zoneConfig = mTestAudioZoneConfigBuilder.addVolumeGroup(mMockMusicGroup)
.addVolumeGroup(mMockNavGroup).build();
List<Integer> reasons = List.of(Reasons.REMOTE_MUTE, Reasons.NAV_DUCKING);
AudioGainConfigInfo musicGainInfo = new AudioGainConfigInfo();
musicGainInfo.zoneId = CarAudioManager.PRIMARY_AUDIO_ZONE;
musicGainInfo.devicePortAddress = MUSIC_ADDRESS;
musicGainInfo.volumeIndex = 666;
CarAudioGainConfigInfo carMusicGainInfo = new CarAudioGainConfigInfo(musicGainInfo);
when(mMockNavGroup.onAudioGainChanged(any(), any())).thenReturn(EVENT_TYPE_MUTE_CHANGED);
when(mMockMusicGroup.onAudioGainChanged(any(), any()))
.thenReturn(EVENT_TYPE_ATTENUATION_CHANGED);
when(mMockVoiceGroup.onAudioGainChanged(any(), any()))
.thenReturn(EVENT_TYPE_ATTENUATION_CHANGED);
List<CarVolumeGroupEvent> events = zoneConfig.onAudioGainChanged(reasons,
List.of(carMusicGainInfo));
expectWithMessage("Changed audio gain").that(events.isEmpty()).isFalse();
verify(mMockMusicGroup).onAudioGainChanged(reasons, carMusicGainInfo);
verify(mMockNavGroup, never()).onAudioGainChanged(any(), any());
verify(mMockVoiceGroup, never()).onAudioGainChanged(any(), any());
}
@Test
public void onAudioGainChanged_withoutAnyDeviceAddressInZone() {
CarAudioZoneConfig zoneConfig = mTestAudioZoneConfigBuilder.addVolumeGroup(mMockVoiceGroup)
.build();
List<Integer> reasons = List.of(Reasons.REMOTE_MUTE, Reasons.NAV_DUCKING);
AudioGainConfigInfo musicGainInfo = new AudioGainConfigInfo();
musicGainInfo.zoneId = CarAudioManager.PRIMARY_AUDIO_ZONE;
musicGainInfo.devicePortAddress = MUSIC_ADDRESS;
musicGainInfo.volumeIndex = 666;
CarAudioGainConfigInfo carMusicGainInfo = new CarAudioGainConfigInfo(musicGainInfo);
when(mMockNavGroup.onAudioGainChanged(any(), any())).thenReturn(EVENT_TYPE_MUTE_CHANGED);
when(mMockMusicGroup.onAudioGainChanged(any(), any()))
.thenReturn(EVENT_TYPE_ATTENUATION_CHANGED);
when(mMockVoiceGroup.onAudioGainChanged(any(), any()))
.thenReturn(EVENT_TYPE_ATTENUATION_CHANGED);
List<CarVolumeGroupEvent> events = zoneConfig.onAudioGainChanged(reasons,
List.of(carMusicGainInfo));
expectWithMessage("Changed audio gain").that(events.isEmpty()).isTrue();
verify(mMockMusicGroup, never()).onAudioGainChanged(any(), any());
verify(mMockNavGroup, never()).onAudioGainChanged(any(), any());
verify(mMockVoiceGroup, never()).onAudioGainChanged(any(), any());
}
@Test
public void getCarVolumeGroupInfos() {
CarAudioZoneConfig zoneConfig = mTestAudioZoneConfigBuilder.addVolumeGroup(mMockMusicGroup)
.addVolumeGroup(mMockNavGroup).addVolumeGroup(mMockVoiceGroup).build();
List<CarVolumeGroupInfo> infos = zoneConfig.getVolumeGroupInfos();
expectWithMessage("Car volume group infos").that(infos).hasSize(3);
}
@Test
public void getCarAudioZoneConfigInfo() {
CarAudioZoneConfig zoneConfig = mTestAudioZoneConfigBuilder.build();
CarAudioZoneConfigInfo zoneConfigInfoExpected = new CarAudioZoneConfigInfo(
TEST_ZONE_CONFIG_NAME, CarAudioManager.PRIMARY_AUDIO_ZONE, TEST_ZONE_CONFIG_ID);
CarAudioZoneConfigInfo zoneConfigInfo = zoneConfig.getCarAudioZoneConfigInfo();
expectWithMessage("Zone configuration info")
.that(zoneConfigInfo).isEqualTo(zoneConfigInfoExpected);
}
private CarAudioZoneConfig buildZoneConfig(List<CarVolumeGroup> volumeGroups) {
CarAudioZoneConfig.Builder carAudioZoneConfigBuilder =
new CarAudioZoneConfig.Builder("Primary zone config 0",
CarAudioManager.PRIMARY_AUDIO_ZONE, /* zoneConfigId= */ 0,
/* isDefault= */ true);
for (int index = 0; index < volumeGroups.size(); index++) {
carAudioZoneConfigBuilder =
carAudioZoneConfigBuilder.addVolumeGroup(volumeGroups.get(index));
}
return carAudioZoneConfigBuilder.build();
}
private CarVolumeGroup mockContextsExceptMediaAndNavigation() {
return new VolumeGroupBuilder()
.addDeviceAddressAndContexts(CarAudioContext.VOICE_COMMAND, VOICE_ADDRESS)
.addDeviceAddressAndContexts(CarAudioContext.CALL_RING, VOICE_ADDRESS)
.addDeviceAddressAndContexts(CarAudioContext.CALL, VOICE_ADDRESS)
.addDeviceAddressAndContexts(CarAudioContext.ALARM, VOICE_ADDRESS)
.addDeviceAddressAndContexts(CarAudioContext.NOTIFICATION, VOICE_ADDRESS)
.addDeviceAddressAndContexts(CarAudioContext.SYSTEM_SOUND, VOICE_ADDRESS)
.addDeviceAddressAndContexts(CarAudioContext.EMERGENCY, VOICE_ADDRESS)
.addDeviceAddressAndContexts(CarAudioContext.SAFETY, VOICE_ADDRESS)
.addDeviceAddressAndContexts(CarAudioContext.VEHICLE_STATUS, VOICE_ADDRESS)
.addDeviceAddressAndContexts(CarAudioContext.ANNOUNCEMENT, VOICE_ADDRESS).build();
}
}