| /* |
| * Copyright (C) 2021 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.media.AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE; |
| import static android.media.AudioAttributes.USAGE_MEDIA; |
| import static android.media.AudioManager.AUDIOFOCUS_GAIN; |
| import static android.media.AudioManager.AUDIOFOCUS_REQUEST_DELAYED; |
| import static android.media.AudioManager.AUDIOFOCUS_REQUEST_GRANTED; |
| |
| import static com.google.common.truth.Truth.assertWithMessage; |
| |
| import static org.junit.Assert.assertThrows; |
| import static org.mockito.ArgumentMatchers.any; |
| import static org.mockito.ArgumentMatchers.eq; |
| import static org.mockito.Mockito.description; |
| import static org.mockito.Mockito.mock; |
| import static org.mockito.Mockito.verify; |
| import static org.mockito.Mockito.when; |
| |
| import android.car.media.CarAudioManager; |
| import android.content.pm.PackageManager; |
| import android.media.AudioAttributes; |
| import android.media.AudioFocusInfo; |
| import android.media.AudioManager; |
| import android.media.audiopolicy.AudioPolicy; |
| import android.os.Build; |
| import android.os.Bundle; |
| import android.util.SparseArray; |
| |
| import com.android.car.CarLocalServices; |
| import com.android.car.oem.CarOemProxyService; |
| |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.mockito.ArgumentCaptor; |
| import org.mockito.Mock; |
| import org.mockito.junit.MockitoJUnitRunner; |
| |
| import java.util.List; |
| |
| @RunWith(MockitoJUnitRunner.class) |
| public final class CarZonesAudioFocusUnitTest { |
| private static final String CLIENT_ID = "media-client-id"; |
| private static final String PACKAGE_NAME = "com.android.car.audio"; |
| private static final int AUDIOFOCUS_FLAG = 0; |
| private static final int PRIMARY_ZONE_ID = CarAudioManager.PRIMARY_AUDIO_ZONE; |
| private static final int SECONDARY_ZONE_ID = CarAudioManager.PRIMARY_AUDIO_ZONE + 1; |
| private static final int CLIENT_UID = 1086753; |
| |
| private final SparseArray<CarAudioFocus> mFocusMocks = generateMockFocus(); |
| private final SparseArray<CarAudioZone> mMockZones = generateAudioZones(); |
| |
| @Mock |
| private AudioManager mMockAudioManager; |
| @Mock |
| private AudioPolicy mAudioPolicy; |
| @Mock |
| private CarAudioService mCarAudioService; |
| @Mock |
| private CarAudioSettings mCarAudioSettings; |
| @Mock |
| private CarZonesAudioFocus.CarFocusCallback mMockCarFocusCallback; |
| @Mock |
| private PackageManager mMockPackageManager; |
| @Mock |
| private CarOemProxyService mMockCarOemProxyService; |
| @Mock |
| private CarVolumeInfoWrapper mMockCarVolumeInfoWrapper; |
| |
| private CarZonesAudioFocus mCarZonesAudioFocus; |
| |
| @Before |
| public void setUp() { |
| mCarZonesAudioFocus = getCarZonesAudioFocus(); |
| CarLocalServices.removeServiceForTest(CarOemProxyService.class); |
| CarLocalServices.addService(CarOemProxyService.class, mMockCarOemProxyService); |
| } |
| |
| @After |
| public void tearDown() { |
| CarLocalServices.removeServiceForTest(CarOemProxyService.class); |
| } |
| |
| @Test |
| public void newCarZonesAudioFocus_withNullAudioManager_throws() { |
| NullPointerException thrown = assertThrows(NullPointerException.class, |
| () -> CarZonesAudioFocus.createCarZonesAudioFocus(null, |
| mMockPackageManager, mMockZones, mCarAudioSettings, mMockCarFocusCallback, |
| mMockCarVolumeInfoWrapper) |
| ); |
| |
| assertWithMessage("Create car audio zone with null audio manager exception") |
| .that(thrown).hasMessageThat().contains("Audio manager"); |
| } |
| |
| @Test |
| public void newCarZonesAudioFocus_withNullPackageManager_throws() { |
| NullPointerException thrown = assertThrows(NullPointerException.class, |
| () -> CarZonesAudioFocus.createCarZonesAudioFocus(mMockAudioManager, |
| null, mMockZones, mCarAudioSettings, mMockCarFocusCallback, |
| mMockCarVolumeInfoWrapper) |
| ); |
| |
| assertWithMessage("Create car audio zone with null package manager exception") |
| .that(thrown).hasMessageThat().contains("Package manager"); |
| } |
| |
| @Test |
| public void newCarZonesAudioFocus_withNullCarAudioZones_throws() { |
| NullPointerException thrown = assertThrows(NullPointerException.class, |
| () -> CarZonesAudioFocus.createCarZonesAudioFocus(mMockAudioManager, |
| mMockPackageManager, null, mCarAudioSettings, mMockCarFocusCallback, |
| mMockCarVolumeInfoWrapper) |
| ); |
| |
| assertWithMessage("Create car audio zone with null zones exception") |
| .that(thrown).hasMessageThat().contains("Car audio zones"); |
| } |
| |
| @Test |
| public void newCarZonesAudioFocus_withEmptyCarAudioZones_throws() { |
| IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, |
| () -> CarZonesAudioFocus.createCarZonesAudioFocus(mMockAudioManager, |
| mMockPackageManager, new SparseArray<>(), mCarAudioSettings, |
| mMockCarFocusCallback, mMockCarVolumeInfoWrapper) |
| ); |
| |
| assertWithMessage("Create car audio zone with no audio zones exception") |
| .that(thrown).hasMessageThat().contains("minimum of one audio zone"); |
| } |
| |
| @Test |
| public void newCarZonesAudioFocus_withNullCarAudioSettings_throws() { |
| NullPointerException thrown = assertThrows(NullPointerException.class, |
| () -> CarZonesAudioFocus.createCarZonesAudioFocus(mMockAudioManager, |
| mMockPackageManager, mMockZones, null, mMockCarFocusCallback, |
| mMockCarVolumeInfoWrapper) |
| ); |
| |
| assertWithMessage("Create car audio zone with null car settings exception") |
| .that(thrown).hasMessageThat().contains("Car audio settings"); |
| } |
| |
| @Test |
| public void newCarZonesAudioFocus_withNullCarFocusCallback_succeeds() { |
| CarZonesAudioFocus.createCarZonesAudioFocus(mMockAudioManager, mMockPackageManager, |
| mMockZones, mCarAudioSettings, null, mMockCarVolumeInfoWrapper); |
| } |
| |
| @Test |
| public void newCarZonesAudioFocus_withNullCarVolumeInfo_succeeds() { |
| NullPointerException thrown = assertThrows(NullPointerException.class, |
| () -> CarZonesAudioFocus.createCarZonesAudioFocus(mMockAudioManager, |
| mMockPackageManager, mMockZones, mCarAudioSettings, mMockCarFocusCallback, |
| /* carVolumeInfo= */ null) |
| ); |
| |
| assertWithMessage("Create car audio zone with null car volume exception") |
| .that(thrown).hasMessageThat().contains("Car volume info"); |
| } |
| |
| @Test |
| public void onAudioFocusRequest_withPrimaryZoneUid_passesRequestToPrimaryZone() { |
| withUidRoutingToZone(PRIMARY_ZONE_ID); |
| AudioFocusInfo audioFocusInfo = generateAudioFocusRequest(); |
| |
| mCarZonesAudioFocus.onAudioFocusRequest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED); |
| |
| verify(mFocusMocks.get(PRIMARY_ZONE_ID)) |
| .onAudioFocusRequest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED); |
| } |
| |
| @Test |
| public void onAudioFocusRequest_withSecondaryZoneUid_passesRequestToSecondaryZone() { |
| withUidRoutingToZone(SECONDARY_ZONE_ID); |
| AudioFocusInfo audioFocusInfo = generateAudioFocusRequest(); |
| |
| mCarZonesAudioFocus.onAudioFocusRequest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED); |
| |
| verify(mFocusMocks.get(SECONDARY_ZONE_ID)) |
| .onAudioFocusRequest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED); |
| } |
| |
| @Test |
| public void onAudioFocusRequest_withValidBundledZoneId_passesRequestToBundledZone() { |
| withUidRoutingToZone(PRIMARY_ZONE_ID); |
| when(mCarAudioService.isAudioZoneIdValid(SECONDARY_ZONE_ID)).thenReturn(true); |
| AudioFocusInfo audioFocusInfo = generateAudioFocusInfoWithBundledZoneId(SECONDARY_ZONE_ID); |
| |
| mCarZonesAudioFocus.onAudioFocusRequest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED); |
| |
| verify(mFocusMocks.get(SECONDARY_ZONE_ID)) |
| .onAudioFocusRequest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED); |
| } |
| |
| @Test |
| public void onAudioFocusRequest_withInvalidBundledZoneId_passesRequestBasedOnUid() { |
| int invalidZoneId = -1; |
| withUidRoutingToZone(PRIMARY_ZONE_ID); |
| when(mCarAudioService.isAudioZoneIdValid(invalidZoneId)).thenReturn(false); |
| AudioFocusInfo audioFocusInfo = generateAudioFocusInfoWithBundledZoneId(invalidZoneId); |
| |
| mCarZonesAudioFocus.onAudioFocusRequest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED); |
| |
| verify(mFocusMocks.get(PRIMARY_ZONE_ID)) |
| .onAudioFocusRequest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED); |
| } |
| |
| @Test |
| public void onAudioFocusRequest_withFocusCallback_callsOnFocusChange() { |
| List<AudioFocusInfo> focusHolders = List.of(generateAudioFocusRequest()); |
| when(mFocusMocks.get(PRIMARY_ZONE_ID).getAudioFocusHolders()).thenReturn(focusHolders); |
| AudioFocusInfo audioFocusInfo = generateAudioFocusRequest(); |
| |
| mCarZonesAudioFocus.onAudioFocusRequest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED); |
| |
| ArgumentCaptor<SparseArray<List<AudioFocusInfo>>> captor = |
| ArgumentCaptor.forClass(SparseArray.class); |
| verify(mMockCarFocusCallback) |
| .onFocusChange(eq(new int[]{PRIMARY_ZONE_ID}), captor.capture()); |
| SparseArray<List<AudioFocusInfo>> results = captor.getValue(); |
| assertWithMessage("Number of lists returned in sparse array") |
| .that(results.size()).isEqualTo(1); |
| assertWithMessage("Focus holders for primary zone") |
| .that(results.get(PRIMARY_ZONE_ID)).isEqualTo(focusHolders); |
| } |
| |
| @Test |
| public void setRestrictFocus_withTrue_restrictsFocusForAllZones() { |
| mCarZonesAudioFocus.setRestrictFocus(true); |
| |
| verify(mFocusMocks.get(PRIMARY_ZONE_ID), |
| description("Primary zone's CarAudioFocus#setRestrictFocus wasn't passed true")) |
| .setRestrictFocus(true); |
| verify(mFocusMocks.get(SECONDARY_ZONE_ID), |
| description("Secondary zone's CarAudioFocus#setRestrictFocus wasn't passed true")) |
| .setRestrictFocus(true); |
| } |
| |
| @Test |
| public void setRestrictFocus_withFalse_unrestrictsFocusForAllZones() { |
| mCarZonesAudioFocus.setRestrictFocus(false); |
| |
| verify(mFocusMocks.get(PRIMARY_ZONE_ID), |
| description("Primary zone's CarAudioFocus#setRestrictFocus wasn't passed false")) |
| .setRestrictFocus(false); |
| verify(mFocusMocks.get(SECONDARY_ZONE_ID), |
| description("Secondary zone's CarAudioFocus#setRestrictFocus wasn't passed false")) |
| .setRestrictFocus(false); |
| } |
| |
| @Test |
| public void setRestrictFocus_notifiesFocusCallbackForAllZones() { |
| mCarZonesAudioFocus.setRestrictFocus(false); |
| |
| ArgumentCaptor<SparseArray<List<AudioFocusInfo>>> captor = |
| ArgumentCaptor.forClass(SparseArray.class); |
| int[] expectedZoneIds = new int[]{PRIMARY_ZONE_ID, SECONDARY_ZONE_ID}; |
| verify(mMockCarFocusCallback).onFocusChange(eq(expectedZoneIds), captor.capture()); |
| assertWithMessage("Number of focus holder lists") |
| .that(captor.getValue().size()).isEqualTo(2); |
| } |
| |
| @Test |
| public void transientlyLoseAllFocusHoldersInZone() { |
| AudioFocusInfo mediaFocusInfo = generateAudioFocusRequest(); |
| AudioFocusInfo navigationFocusInfo = |
| generateAudioFocusRequestWithUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE); |
| List<AudioFocusInfo> expectedFocusInfoList = List.of(mediaFocusInfo, navigationFocusInfo); |
| when(mFocusMocks.get(SECONDARY_ZONE_ID).getAudioFocusHolders()) |
| .thenReturn(expectedFocusInfoList); |
| |
| List<AudioFocusInfo> audioFocusInfos = |
| mCarZonesAudioFocus.transientlyLoseAllFocusHoldersInZone(SECONDARY_ZONE_ID); |
| |
| verify(mFocusMocks.get(SECONDARY_ZONE_ID)) |
| .removeAudioFocusInfoAndTransientlyLoseFocus(mediaFocusInfo); |
| verify(mFocusMocks.get(SECONDARY_ZONE_ID)) |
| .removeAudioFocusInfoAndTransientlyLoseFocus(navigationFocusInfo); |
| assertWithMessage("Focus holders in secondary zone") |
| .that(audioFocusInfos).containsExactlyElementsIn(expectedFocusInfoList); |
| } |
| |
| @Test |
| public void reevaluateAndRegainAudioFocusList_regainsFocus() { |
| AudioFocusInfo mediaFocusInfo = generateAudioFocusRequest(); |
| AudioFocusInfo navigationFocusInfo = |
| generateAudioFocusRequestWithUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE); |
| int mediaFocusRequestResult = AUDIOFOCUS_REQUEST_DELAYED; |
| int navigationFocusRequestResult = AUDIOFOCUS_REQUEST_GRANTED; |
| when(mCarAudioService.getZoneIdForAudioFocusInfo(mediaFocusInfo)) |
| .thenReturn(PRIMARY_ZONE_ID); |
| when(mCarAudioService.getZoneIdForAudioFocusInfo(navigationFocusInfo)) |
| .thenReturn(SECONDARY_ZONE_ID); |
| when(mFocusMocks.get(PRIMARY_ZONE_ID).reevaluateAndRegainAudioFocus(any())) |
| .thenReturn(mediaFocusRequestResult); |
| when(mFocusMocks.get(SECONDARY_ZONE_ID).reevaluateAndRegainAudioFocus(any())) |
| .thenReturn(navigationFocusRequestResult); |
| |
| List<Integer> resList = mCarZonesAudioFocus.reevaluateAndRegainAudioFocusList( |
| List.of(mediaFocusInfo, navigationFocusInfo)); |
| |
| assertWithMessage("Result list size").that(resList.size()).isEqualTo(2); |
| assertWithMessage("Results for regaining media focus in primary zone") |
| .that(resList.get(0)).isEqualTo(mediaFocusRequestResult); |
| assertWithMessage("Results for regaining navigation focus in primary zone") |
| .that(resList.get(1)).isEqualTo(navigationFocusRequestResult); |
| } |
| |
| @Test |
| public void reevaluateAndRegainAudioFocusList_notifiesFocusListener() { |
| AudioFocusInfo mediaFocusInfo = generateAudioFocusRequest(); |
| AudioFocusInfo navigationFocusInfo = |
| generateAudioFocusRequestWithUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE); |
| when(mCarAudioService.getZoneIdForAudioFocusInfo(mediaFocusInfo)) |
| .thenReturn(PRIMARY_ZONE_ID); |
| when(mCarAudioService.getZoneIdForAudioFocusInfo(navigationFocusInfo)) |
| .thenReturn(SECONDARY_ZONE_ID); |
| when(mFocusMocks.get(PRIMARY_ZONE_ID).getAudioFocusHolders()) |
| .thenReturn(List.of(mediaFocusInfo)); |
| when(mFocusMocks.get(SECONDARY_ZONE_ID).getAudioFocusHolders()) |
| .thenReturn(List.of(navigationFocusInfo)); |
| |
| mCarZonesAudioFocus.reevaluateAndRegainAudioFocusList(List.of(mediaFocusInfo, |
| navigationFocusInfo)); |
| |
| ArgumentCaptor<SparseArray<List<AudioFocusInfo>>> captor = |
| ArgumentCaptor.forClass(SparseArray.class); |
| verify(mMockCarFocusCallback).onFocusChange( |
| eq(new int[]{PRIMARY_ZONE_ID, SECONDARY_ZONE_ID}), captor.capture()); |
| SparseArray<List<AudioFocusInfo>> results = captor.getValue(); |
| assertWithMessage("Zones notified for focus changed") |
| .that(results.size()).isEqualTo(2); |
| assertWithMessage("Primary zone focus holders") |
| .that(results.get(PRIMARY_ZONE_ID)).containsExactly(mediaFocusInfo); |
| assertWithMessage("Secondary zone focus holders") |
| .that(results.get(SECONDARY_ZONE_ID)).containsExactly(navigationFocusInfo); |
| } |
| |
| @Test |
| public void transientlyLoseAudioFocusForZone_forActiveFocusHolders() { |
| AudioFocusInfo mediaFocusInfo = generateAudioFocusRequest(); |
| AudioFocusInfo navigationFocusInfo = |
| generateAudioFocusRequestWithUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE); |
| List<AudioFocusInfo> expectedFocusInfoList = List.of(mediaFocusInfo, navigationFocusInfo); |
| when(mFocusMocks.get(SECONDARY_ZONE_ID).getAudioFocusHolders()) |
| .thenReturn(expectedFocusInfoList); |
| when(mFocusMocks.get(SECONDARY_ZONE_ID).getAudioFocusLosers()).thenReturn(List.of()); |
| |
| AudioFocusStack stack = |
| mCarZonesAudioFocus.transientlyLoseAudioFocusForZone(SECONDARY_ZONE_ID); |
| |
| verify(mFocusMocks.get(SECONDARY_ZONE_ID)) |
| .removeAudioFocusInfoAndTransientlyLoseFocus(mediaFocusInfo); |
| verify(mFocusMocks.get(SECONDARY_ZONE_ID)) |
| .removeAudioFocusInfoAndTransientlyLoseFocus(navigationFocusInfo); |
| assertWithMessage("Stack active focus in secondary zone") |
| .that(stack.getActiveFocusList()).containsExactlyElementsIn(expectedFocusInfoList); |
| assertWithMessage("Empty stack inactive focus in secondary zone") |
| .that(stack.getInactiveFocusList()).isEmpty(); |
| } |
| |
| @Test |
| public void transientlyLoseAudioFocusForZone_forInactiveFocusHolders() { |
| AudioFocusInfo mediaFocusInfo = generateAudioFocusRequest(); |
| AudioFocusInfo navigationFocusInfo = |
| generateAudioFocusRequestWithUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE); |
| List<AudioFocusInfo> expectedFocusInfoList = List.of(mediaFocusInfo, navigationFocusInfo); |
| when(mFocusMocks.get(SECONDARY_ZONE_ID).getAudioFocusLosers()) |
| .thenReturn(expectedFocusInfoList); |
| when(mFocusMocks.get(SECONDARY_ZONE_ID).getAudioFocusHolders()).thenReturn(List.of()); |
| |
| AudioFocusStack stack = |
| mCarZonesAudioFocus.transientlyLoseAudioFocusForZone(SECONDARY_ZONE_ID); |
| |
| verify(mFocusMocks.get(SECONDARY_ZONE_ID)) |
| .removeAudioFocusInfoAndTransientlyLoseFocus(mediaFocusInfo); |
| verify(mFocusMocks.get(SECONDARY_ZONE_ID)) |
| .removeAudioFocusInfoAndTransientlyLoseFocus(navigationFocusInfo); |
| assertWithMessage("Stack inactive focus in secondary zone") |
| .that(stack.getInactiveFocusList()) |
| .containsExactlyElementsIn(expectedFocusInfoList); |
| assertWithMessage("Empty stack active focus in secondary zone") |
| .that(stack.getActiveFocusList()).isEmpty(); |
| } |
| |
| private static SparseArray<CarAudioZone> generateAudioZones() { |
| CarAudioContext testCarAudioContext = |
| new CarAudioContext(CarAudioContext.getAllContextsInfo(), |
| /* useCoreAudioRouting= */ false); |
| int zoneConfigId = 0; |
| CarAudioZoneConfig primaryZoneConfig = |
| new CarAudioZoneConfig.Builder("Primary zone config", |
| PRIMARY_ZONE_ID, zoneConfigId, /* isDefault= */ true) |
| .build(); |
| CarAudioZoneConfig secondaryZoneConfig = |
| new CarAudioZoneConfig.Builder("Secondary zone config", |
| SECONDARY_ZONE_ID, zoneConfigId, /* isDefault= */ true) |
| .build(); |
| CarAudioZone primaryZone = new CarAudioZone(testCarAudioContext, "Primary zone", |
| PRIMARY_ZONE_ID); |
| CarAudioZone secondaryZone = new CarAudioZone(testCarAudioContext, "Secondary zone", |
| SECONDARY_ZONE_ID); |
| primaryZone.addZoneConfig(primaryZoneConfig); |
| secondaryZone.addZoneConfig(secondaryZoneConfig); |
| SparseArray<CarAudioZone> zones = new SparseArray<>(); |
| zones.put(PRIMARY_ZONE_ID, primaryZone); |
| zones.put(SECONDARY_ZONE_ID, secondaryZone); |
| return zones; |
| } |
| |
| private static SparseArray<CarAudioFocus> generateMockFocus() { |
| SparseArray<CarAudioFocus> mockFocusZones = new SparseArray<>(); |
| mockFocusZones.put(PRIMARY_ZONE_ID, mock(CarAudioFocus.class)); |
| mockFocusZones.put(SECONDARY_ZONE_ID, mock(CarAudioFocus.class)); |
| return mockFocusZones; |
| } |
| |
| private static AudioFocusInfo generateAudioFocusRequest() { |
| return generateAudioFocusRequestWithUsage(USAGE_MEDIA); |
| } |
| |
| private static AudioFocusInfo generateAudioFocusRequestWithUsage( |
| @AudioAttributes.AttributeSdkUsage int usage) { |
| AudioAttributes attributes = new AudioAttributes.Builder().setUsage(usage).build(); |
| return generateAudioFocusInfoWithAttributes(attributes); |
| } |
| |
| private static AudioFocusInfo generateAudioFocusInfoWithBundledZoneId(int zoneId) { |
| Bundle bundle = new Bundle(); |
| bundle.putInt(CarAudioManager.AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID, zoneId); |
| |
| AudioAttributes attributes = new AudioAttributes.Builder() |
| .setUsage(USAGE_MEDIA) |
| .addBundle(bundle) |
| .build(); |
| return generateAudioFocusInfoWithAttributes(attributes); |
| } |
| |
| private static AudioFocusInfo generateAudioFocusInfoWithAttributes(AudioAttributes attributes) { |
| return new AudioFocusInfo(attributes, CLIENT_UID, CLIENT_ID, |
| PACKAGE_NAME, AUDIOFOCUS_GAIN, AudioManager.AUDIOFOCUS_NONE, AUDIOFOCUS_FLAG, |
| Build.VERSION.SDK_INT); |
| } |
| |
| private CarZonesAudioFocus getCarZonesAudioFocus() { |
| CarZonesAudioFocus carZonesAudioFocus = |
| new CarZonesAudioFocus(mFocusMocks, mMockCarFocusCallback); |
| carZonesAudioFocus.setOwningPolicy(mCarAudioService, mAudioPolicy); |
| |
| return carZonesAudioFocus; |
| } |
| |
| private void withUidRoutingToZone(int zoneId) { |
| when(mCarAudioService.getZoneIdForAudioFocusInfo(any())).thenReturn(zoneId); |
| } |
| } |