| /* |
| * Copyright (C) 2022 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.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS; |
| import static android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME; |
| import static android.car.media.CarAudioManager.AUDIO_FEATURE_AUDIO_MIRRORING; |
| import static android.car.media.CarAudioManager.AUDIO_FEATURE_DYNAMIC_ROUTING; |
| import static android.car.media.CarAudioManager.AUDIO_FEATURE_OEM_AUDIO_SERVICE; |
| import static android.car.media.CarAudioManager.AUDIO_FEATURE_VOLUME_GROUP_EVENTS; |
| import static android.car.media.CarAudioManager.AUDIO_FEATURE_VOLUME_GROUP_MUTING; |
| import static android.car.media.CarAudioManager.INVALID_AUDIO_ZONE; |
| import static android.car.media.CarAudioManager.INVALID_REQUEST_ID; |
| import static android.car.media.CarAudioManager.INVALID_VOLUME_GROUP_ID; |
| import static android.car.media.CarAudioManager.PRIMARY_AUDIO_ZONE; |
| import static android.car.test.mocks.AndroidMockitoHelper.mockContextCheckCallingOrSelfPermission; |
| import static android.content.pm.PackageManager.PERMISSION_DENIED; |
| import static android.content.pm.PackageManager.PERMISSION_GRANTED; |
| import static android.media.AudioAttributes.USAGE_ALARM; |
| import static android.media.AudioAttributes.USAGE_ANNOUNCEMENT; |
| import static android.media.AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY; |
| import static android.media.AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE; |
| import static android.media.AudioAttributes.USAGE_ASSISTANCE_SONIFICATION; |
| import static android.media.AudioAttributes.USAGE_ASSISTANT; |
| import static android.media.AudioAttributes.USAGE_CALL_ASSISTANT; |
| import static android.media.AudioAttributes.USAGE_EMERGENCY; |
| import static android.media.AudioAttributes.USAGE_GAME; |
| import static android.media.AudioAttributes.USAGE_MEDIA; |
| import static android.media.AudioAttributes.USAGE_NOTIFICATION; |
| import static android.media.AudioAttributes.USAGE_NOTIFICATION_EVENT; |
| import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE; |
| import static android.media.AudioAttributes.USAGE_SAFETY; |
| import static android.media.AudioAttributes.USAGE_UNKNOWN; |
| import static android.media.AudioAttributes.USAGE_VEHICLE_STATUS; |
| import static android.media.AudioAttributes.USAGE_VOICE_COMMUNICATION; |
| import static android.media.AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING; |
| import static android.media.AudioDeviceInfo.TYPE_BUILTIN_MIC; |
| import static android.media.AudioDeviceInfo.TYPE_FM_TUNER; |
| import static android.media.AudioManager.AUDIOFOCUS_GAIN; |
| import static android.media.AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK; |
| import static android.media.AudioManager.AUDIOFOCUS_LOSS; |
| import static android.media.AudioManager.AUDIOFOCUS_LOSS_TRANSIENT; |
| import static android.media.AudioManager.AUDIOFOCUS_NONE; |
| import static android.media.AudioManager.AUDIOFOCUS_REQUEST_GRANTED; |
| import static android.media.AudioManager.EXTRA_VOLUME_STREAM_TYPE; |
| import static android.media.AudioManager.FLAG_FROM_KEY; |
| import static android.media.AudioManager.FLAG_SHOW_UI; |
| import static android.media.AudioManager.MASTER_MUTE_CHANGED_ACTION; |
| import static android.media.AudioManager.STREAM_MUSIC; |
| import static android.media.AudioManager.SUCCESS; |
| import static android.media.AudioManager.VOLUME_CHANGED_ACTION; |
| import static android.media.audio.common.AudioDeviceDescription.CONNECTION_BUS; |
| import static android.media.audio.common.AudioDeviceType.OUT_DEVICE; |
| import static android.media.audio.common.AudioGainMode.JOINT; |
| import static android.os.Build.VERSION.SDK_INT; |
| import static android.view.KeyEvent.ACTION_DOWN; |
| import static android.view.KeyEvent.ACTION_UP; |
| import static android.view.KeyEvent.KEYCODE_UNKNOWN; |
| import static android.view.KeyEvent.KEYCODE_VOLUME_DOWN; |
| import static android.view.KeyEvent.KEYCODE_VOLUME_MUTE; |
| import static android.view.KeyEvent.KEYCODE_VOLUME_UP; |
| |
| import static com.android.car.R.bool.audioPersistMasterMuteState; |
| import static com.android.car.R.bool.audioUseCarVolumeGroupEvent; |
| import static com.android.car.R.bool.audioUseCarVolumeGroupMuting; |
| import static com.android.car.R.bool.audioUseCoreRouting; |
| import static com.android.car.R.bool.audioUseCoreVolume; |
| import static com.android.car.R.bool.audioUseDynamicRouting; |
| import static com.android.car.R.bool.audioUseHalDuckingSignals; |
| import static com.android.car.R.integer.audioVolumeAdjustmentContextsVersion; |
| import static com.android.car.R.integer.audioVolumeKeyEventTimeoutMs; |
| import static com.android.car.audio.CarAudioService.CAR_DEFAULT_AUDIO_ATTRIBUTE; |
| import static com.android.car.audio.GainBuilder.DEFAULT_GAIN; |
| import static com.android.car.audio.GainBuilder.MAX_GAIN; |
| import static com.android.car.audio.GainBuilder.MIN_GAIN; |
| import static com.android.car.audio.GainBuilder.STEP_SIZE; |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; |
| |
| import static org.junit.Assert.assertThrows; |
| import static org.mockito.ArgumentMatchers.any; |
| import static org.mockito.ArgumentMatchers.anyBoolean; |
| import static org.mockito.ArgumentMatchers.anyInt; |
| import static org.mockito.ArgumentMatchers.anyString; |
| import static org.mockito.ArgumentMatchers.eq; |
| import static org.mockito.Mockito.atLeastOnce; |
| import static org.mockito.Mockito.mock; |
| import static org.mockito.Mockito.never; |
| import static org.mockito.Mockito.reset; |
| import static org.mockito.Mockito.times; |
| import static org.mockito.Mockito.when; |
| |
| import android.annotation.NonNull; |
| import android.car.Car; |
| import android.car.CarOccupantZoneManager; |
| import android.car.ICarOccupantZoneCallback; |
| import android.car.VehicleAreaSeat; |
| import android.car.builtin.media.AudioManagerHelper; |
| import android.car.builtin.media.AudioManagerHelper.AudioPatchInfo; |
| import android.car.builtin.os.UserManagerHelper; |
| import android.car.media.CarAudioManager; |
| import android.car.media.CarAudioPatchHandle; |
| import android.car.media.CarAudioZoneConfigInfo; |
| import android.car.media.CarVolumeGroupInfo; |
| import android.car.media.IAudioZonesMirrorStatusCallback; |
| import android.car.media.IMediaAudioRequestStatusCallback; |
| import android.car.media.IPrimaryZoneMediaAudioRequestCallback; |
| import android.car.media.ISwitchAudioZoneConfigCallback; |
| import android.car.settings.CarSettings; |
| import android.car.test.mocks.AbstractExtendedMockitoTestCase; |
| import android.car.test.mocks.MockSettings; |
| import android.content.BroadcastReceiver; |
| import android.content.ContentResolver; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.pm.PackageManager; |
| import android.content.res.Resources; |
| import android.hardware.automotive.audiocontrol.AudioGainConfigInfo; |
| import android.hardware.automotive.audiocontrol.IAudioControl; |
| import android.hardware.automotive.audiocontrol.Reasons; |
| import android.media.AudioAttributes; |
| import android.media.AudioDeviceAttributes; |
| import android.media.AudioDeviceInfo; |
| import android.media.AudioFocusInfo; |
| import android.media.AudioGain; |
| import android.media.AudioManager; |
| import android.media.AudioManager.AudioPlaybackCallback; |
| import android.media.AudioPlaybackConfiguration; |
| import android.media.IAudioService; |
| import android.media.audio.common.AudioDevice; |
| import android.media.audio.common.AudioDeviceAddress; |
| import android.media.audio.common.AudioDeviceDescription; |
| import android.media.audio.common.AudioPort; |
| import android.media.audio.common.AudioPortDeviceExt; |
| import android.media.audio.common.AudioPortExt; |
| import android.media.audiopolicy.AudioPolicy; |
| import android.net.Uri; |
| import android.os.Binder; |
| import android.os.Build; |
| import android.os.IBinder; |
| import android.os.RemoteException; |
| import android.os.ServiceManager; |
| import android.os.SystemProperties; |
| import android.os.UserHandle; |
| import android.provider.Settings; |
| import android.telephony.TelephonyManager; |
| import android.util.Log; |
| import android.view.KeyEvent; |
| |
| import androidx.test.core.app.ApplicationProvider; |
| |
| import com.android.car.CarInputService; |
| import com.android.car.CarLocalServices; |
| import com.android.car.CarOccupantZoneService; |
| import com.android.car.R; |
| import com.android.car.audio.hal.AudioControlFactory; |
| import com.android.car.audio.hal.AudioControlWrapper; |
| import com.android.car.audio.hal.AudioControlWrapper.AudioControlDeathRecipient; |
| import com.android.car.audio.hal.AudioControlWrapperAidl; |
| import com.android.car.audio.hal.HalAudioDeviceInfo; |
| import com.android.car.audio.hal.HalAudioGainCallback; |
| import com.android.car.audio.hal.HalAudioModuleChangeCallback; |
| import com.android.car.audio.hal.HalFocusListener; |
| import com.android.car.oem.CarOemAudioDuckingProxyService; |
| import com.android.car.oem.CarOemAudioFocusProxyService; |
| import com.android.car.oem.CarOemAudioVolumeProxyService; |
| import com.android.car.oem.CarOemProxyService; |
| import com.android.car.test.utils.TemporaryFile; |
| |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.mockito.ArgumentCaptor; |
| import org.mockito.Captor; |
| import org.mockito.Mock; |
| |
| import java.io.InputStream; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.concurrent.CountDownLatch; |
| import java.util.concurrent.TimeUnit; |
| |
| public final class CarAudioServiceUnitTest extends AbstractExtendedMockitoTestCase { |
| private static final String TAG = CarAudioServiceUnitTest.class.getSimpleName(); |
| private static final long TEST_CALLBACK_TIMEOUT_MS = 100; |
| private static final int VOLUME_KEY_EVENT_TIMEOUT_MS = 3000; |
| private static final int AUDIO_CONTEXT_PRIORITY_LIST_VERSION_ONE = 1; |
| private static final int AUDIO_CONTEXT_PRIORITY_LIST_VERSION_TWO = 2; |
| private static final String MEDIA_TEST_DEVICE = "media_bus_device"; |
| private static final String OEM_TEST_DEVICE = "oem_bus_device"; |
| private static final String MIRROR_TEST_DEVICE = "mirror_bus_device"; |
| private static final String NAVIGATION_TEST_DEVICE = "navigation_bus_device"; |
| private static final String CALL_TEST_DEVICE = "call_bus_device"; |
| private static final String NOTIFICATION_TEST_DEVICE = "notification_bus_device"; |
| private static final String VOICE_TEST_DEVICE = "voice_bus_device"; |
| private static final String RING_TEST_DEVICE = "ring_bus_device"; |
| private static final String ALARM_TEST_DEVICE = "alarm_bus_device"; |
| private static final String SYSTEM_BUS_DEVICE = "system_bus_device"; |
| private static final String SECONDARY_TEST_DEVICE_1 = "secondary_zone_bus_1"; |
| private static final String SECONDARY_TEST_DEVICE_2 = "secondary_zone_bus_2"; |
| private static final String TERTIARY_TEST_DEVICE_1 = "tertiary_zone_bus_1"; |
| private static final String TERTIARY_TEST_DEVICE_2 = "tertiary_zone_bus_2"; |
| private static final String QUATERNARY_TEST_DEVICE_1 = "quaternary_zone_bus_1"; |
| private static final String PRIMARY_ZONE_MICROPHONE_ADDRESS = "Built-In Mic"; |
| private static final String PRIMARY_ZONE_FM_TUNER_ADDRESS = "FM Tuner"; |
| private static final String SECONDARY_ZONE_CONFIG_NAME_1 = "secondary zone config 1"; |
| private static final String SECONDARY_ZONE_CONFIG_NAME_2 = "secondary zone config 2"; |
| // From the car audio configuration file in /res/raw/car_audio_configuration.xml |
| private static final int TEST_REAR_LEFT_ZONE_ID = 1; |
| private static final int TEST_REAR_RIGHT_ZONE_ID = 2; |
| private static final int TEST_FRONT_ZONE_ID = 3; |
| public static final int[] TEST_MIRROR_AUDIO_ZONES = new int[]{TEST_REAR_LEFT_ZONE_ID, |
| TEST_REAR_RIGHT_ZONE_ID}; |
| private static final int OUT_OF_RANGE_ZONE = TEST_FRONT_ZONE_ID + 1; |
| private static final int PRIMARY_ZONE_VOLUME_GROUP_COUNT = 4; |
| private static final int SECONDARY_ZONE_VOLUME_GROUP_COUNT = 1; |
| private static final int SECONDARY_ZONE_VOLUME_GROUP_ID = SECONDARY_ZONE_VOLUME_GROUP_COUNT - 1; |
| private static final int TEST_PRIMARY_GROUP = 0; |
| private static final int TEST_SECONDARY_GROUP = 1; |
| private static final int TEST_THIRD_GROUP = 2; |
| private static final int TEST_PRIMARY_GROUP_INDEX = 0; |
| private static final int TEST_FLAGS = 0; |
| private static final float TEST_VALUE = -.75f; |
| private static final float INVALID_TEST_VALUE = -1.5f; |
| private static final int TEST_DISPLAY_TYPE = 2; |
| private static final int TEST_SEAT = 2; |
| private static final int PRIMARY_OCCUPANT_ZONE = 0; |
| private static final int INVALID_STATUS = 0; |
| |
| private static final int TEST_DRIVER_OCCUPANT_ZONE_ID = 1; |
| private static final int TEST_REAR_LEFT_OCCUPANT_ZONE_ID = 2; |
| private static final int TEST_REAR_RIGHT_OCCUPANT_ZONE_ID = 3; |
| private static final int TEST_FRONT_OCCUPANT_ZONE_ID = 4; |
| private static final int TEST_UNASSIGNED_OCCUPANT_ZONE_ID = 5; |
| |
| private static final int TEST_MEDIA_PORT_ID = 0; |
| private static final int TEST_NAV_PORT_ID = 1; |
| private static final String TEST_MEDIA_PORT_NAME = "Media bus"; |
| private static final String TEST_NAV_PORT_NAME = "Nav bus"; |
| private static final int TEST_GAIN_MIN_VALUE = -3000; |
| private static final int TEST_GAIN_MAX_VALUE = -1000; |
| private static final int TEST_GAIN_DEFAULT_VALUE = -2000; |
| private static final int TEST_GAIN_STEP_VALUE = 2; |
| |
| private static final CarOccupantZoneManager.OccupantZoneInfo TEST_DRIVER_OCCUPANT = |
| getOccupantInfo(TEST_DRIVER_OCCUPANT_ZONE_ID, |
| CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER, |
| VehicleAreaSeat.SEAT_ROW_1_LEFT); |
| private static final CarOccupantZoneManager.OccupantZoneInfo |
| TEST_REAR_RIGHT_PASSENGER_OCCUPANT = |
| getOccupantInfo(TEST_REAR_RIGHT_OCCUPANT_ZONE_ID, |
| CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER, |
| VehicleAreaSeat.SEAT_ROW_2_RIGHT); |
| private static final CarOccupantZoneManager.OccupantZoneInfo |
| TEST_FRONT_PASSENGER_OCCUPANT = |
| getOccupantInfo(TEST_FRONT_OCCUPANT_ZONE_ID, |
| CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER, |
| VehicleAreaSeat.SEAT_ROW_1_RIGHT); |
| private static final CarOccupantZoneManager.OccupantZoneInfo |
| TEST_REAR_LEFT_PASSENGER_OCCUPANT = |
| getOccupantInfo(TEST_REAR_LEFT_OCCUPANT_ZONE_ID, |
| CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER, |
| VehicleAreaSeat.SEAT_ROW_2_LEFT); |
| |
| private static final String PROPERTY_RO_ENABLE_AUDIO_PATCH = |
| "ro.android.car.audio.enableaudiopatch"; |
| |
| private static final int MEDIA_APP_UID = 1086753; |
| private static final int TEST_REAR_RIGHT_UID = 1286753; |
| private static final String MEDIA_CLIENT_ID = "media-client-id"; |
| private static final String MEDIA_PACKAGE_NAME = "com.android.car.audio"; |
| private static final int MEDIA_EMPTY_FLAG = 0; |
| private static final String REGISTRATION_ID = "meh"; |
| private static final int MEDIA_VOLUME_GROUP_ID = 0; |
| private static final int NAVIGATION_VOLUME_GROUP_ID = 1; |
| private static final int INVALID_USAGE = -1; |
| private static final int INVALID_AUDIO_FEATURE = -1; |
| private static final int TEST_DRIVER_USER_ID = 10; |
| private static final int TEST_REAR_LEFT_USER_ID = 11; |
| private static final int TEST_REAR_RIGHT_USER_ID = 12; |
| private static final int TEST_FRONT_PASSEGNER_USER_ID = 13; |
| private static final int TEST_GAIN_INDEX = 4; |
| |
| private static final List<AudioAttributes> TEST_PRIMARY_AUDIO_ATTRIBUTES = List.of( |
| CarAudioContext.getAudioAttributeFromUsage(USAGE_UNKNOWN), |
| CarAudioContext.getAudioAttributeFromUsage(USAGE_GAME), |
| CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA), |
| CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION), |
| CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION_EVENT), |
| CarAudioContext.getAudioAttributeFromUsage(USAGE_ANNOUNCEMENT)); |
| |
| private static final List<AudioAttributes> TEST_SECONDARY_AUDIO_ATTRIBUTES = List.of( |
| CarAudioContext.getAudioAttributeFromUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE), |
| CarAudioContext.getAudioAttributeFromUsage(USAGE_ASSISTANCE_ACCESSIBILITY), |
| CarAudioContext.getAudioAttributeFromUsage(USAGE_ASSISTANT)); |
| |
| private static final CarVolumeGroupInfo TEST_PRIMARY_VOLUME_INFO = |
| new CarVolumeGroupInfo.Builder("group id " + TEST_PRIMARY_GROUP, PRIMARY_AUDIO_ZONE, |
| TEST_PRIMARY_GROUP).setMuted(true).setMinVolumeGainIndex(0) |
| .setMaxVolumeGainIndex(MAX_GAIN / STEP_SIZE) |
| .setVolumeGainIndex(DEFAULT_GAIN / STEP_SIZE) |
| .setAudioAttributes(TEST_PRIMARY_AUDIO_ATTRIBUTES).build(); |
| |
| private static final CarVolumeGroupInfo TEST_SECONDARY_VOLUME_INFO = |
| new CarVolumeGroupInfo.Builder("group id " + TEST_SECONDARY_GROUP, PRIMARY_AUDIO_ZONE, |
| TEST_SECONDARY_GROUP).setMuted(true).setMinVolumeGainIndex(0) |
| .setMaxVolumeGainIndex(MAX_GAIN / STEP_SIZE) |
| .setAudioAttributes(TEST_SECONDARY_AUDIO_ATTRIBUTES) |
| .setVolumeGainIndex(DEFAULT_GAIN / STEP_SIZE).build(); |
| |
| private static final AudioDeviceInfo MICROPHONE_TEST_DEVICE = |
| new AudioDeviceInfoBuilder().setAddressName(PRIMARY_ZONE_MICROPHONE_ADDRESS) |
| .setType(TYPE_BUILTIN_MIC) |
| .setIsSource(true) |
| .build(); |
| private static final AudioDeviceInfo FM_TUNER_TEST_DEVICE = |
| new AudioDeviceInfoBuilder().setAddressName(PRIMARY_ZONE_FM_TUNER_ADDRESS) |
| .setType(TYPE_FM_TUNER) |
| .setIsSource(true) |
| .build(); |
| |
| private static final AudioFocusInfo TEST_AUDIO_FOCUS_INFO = |
| new AudioFocusInfo(CarAudioContext |
| .getAudioAttributeFromUsage(USAGE_VOICE_COMMUNICATION), MEDIA_APP_UID, |
| MEDIA_CLIENT_ID, "com.android.car.audio", |
| AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, AUDIOFOCUS_NONE, /* loss= */ 0, |
| Build.VERSION.SDK_INT); |
| |
| private static final AudioFocusInfo TEST_REAR_RIGHT_AUDIO_FOCUS_INFO = |
| new AudioFocusInfo(CarAudioContext |
| .getAudioAttributeFromUsage(USAGE_MEDIA), TEST_REAR_RIGHT_UID, |
| MEDIA_CLIENT_ID, "com.android.car.audio", |
| AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, AUDIOFOCUS_NONE, /* loss= */ 0, |
| Build.VERSION.SDK_INT); |
| |
| private CarAudioService mCarAudioService; |
| @Mock |
| private Context mMockContext; |
| @Mock |
| private TelephonyManager mMockTelephonyManager; |
| @Mock |
| private AudioManager mAudioManager; |
| @Mock |
| private Resources mMockResources; |
| @Mock |
| private ContentResolver mMockContentResolver; |
| @Mock |
| IBinder mBinder; |
| @Mock |
| IBinder mVolumeCallbackBinder; |
| @Mock |
| IAudioControl mAudioControl; |
| @Mock |
| private PackageManager mMockPackageManager; |
| @Mock |
| private CarOccupantZoneService mMockOccupantZoneService; |
| @Mock |
| private CarOemProxyService mMockCarOemProxyService; |
| @Mock |
| private IAudioService mMockAudioService; |
| @Mock |
| private Uri mNavSettingUri; |
| @Mock |
| private AudioControlWrapperAidl mAudioControlWrapperAidl; |
| @Mock |
| private CarVolumeCallbackHandler mCarVolumeCallbackHandler; |
| @Mock |
| private CarInputService mMockCarInputService; |
| |
| // Not used directly, but sets proper mockStatic() expectations on Settings |
| @SuppressWarnings("UnusedVariable") |
| private MockSettings mMockSettings; |
| |
| private boolean mPersistMasterMute = true; |
| private boolean mUseDynamicRouting = true; |
| private boolean mUseHalAudioDucking = true; |
| private boolean mUseCarVolumeGroupMuting = true; |
| private boolean mUseCarVolumeGroupEvents = true; |
| |
| private TemporaryFile mTemporaryAudioConfigurationUsingCoreAudioFile; |
| private TemporaryFile mTemporaryAudioConfigurationFile; |
| private TemporaryFile mTemporaryAudioConfigurationWithoutZoneMappingFile; |
| private TemporaryFile mTemporaryAudioConfigurationWithoutMirroringFile; |
| private Context mContext; |
| private AudioDeviceInfo mMicrophoneInputDevice; |
| private AudioDeviceInfo mFmTunerInputDevice; |
| private AudioDeviceInfo mMediaOutputDevice; |
| |
| @Captor |
| private ArgumentCaptor<BroadcastReceiver> mVolumeReceiverCaptor; |
| |
| public CarAudioServiceUnitTest() { |
| super(CarAudioService.TAG); |
| } |
| |
| @Override |
| protected void onSessionBuilder(CustomMockitoSessionBuilder session) { |
| mMockSettings = new MockSettings(session); |
| session |
| .spyStatic(AudioManager.class) |
| .spyStatic(AudioManagerHelper.class) |
| .spyStatic(AudioControlWrapperAidl.class) |
| .spyStatic(AudioControlFactory.class) |
| .spyStatic(SystemProperties.class) |
| .spyStatic(ServiceManager.class); |
| } |
| |
| @Before |
| public void setUp() throws Exception { |
| mContext = ApplicationProvider.getApplicationContext(); |
| |
| try (InputStream configurationStream = mContext.getResources().openRawResource( |
| R.raw.car_audio_configuration)) { |
| mTemporaryAudioConfigurationFile = new TemporaryFile("xml"); |
| mTemporaryAudioConfigurationFile.write(new String(configurationStream.readAllBytes())); |
| Log.i(TAG, "Temporary Car Audio Configuration File Location: " |
| + mTemporaryAudioConfigurationFile.getPath()); |
| } |
| |
| try (InputStream configurationStream = mContext.getResources().openRawResource( |
| R.raw.car_audio_configuration_without_zone_mapping)) { |
| mTemporaryAudioConfigurationWithoutZoneMappingFile = new TemporaryFile("xml"); |
| mTemporaryAudioConfigurationWithoutZoneMappingFile |
| .write(new String(configurationStream.readAllBytes())); |
| Log.i(TAG, "Temporary Car Audio Configuration without Zone mapping File Location: " |
| + mTemporaryAudioConfigurationWithoutZoneMappingFile.getPath()); |
| } |
| |
| try (InputStream configurationStream = mContext.getResources().openRawResource( |
| R.raw.car_audio_configuration_using_core_audio_routing_and_volume)) { |
| mTemporaryAudioConfigurationUsingCoreAudioFile = new TemporaryFile("xml"); |
| mTemporaryAudioConfigurationUsingCoreAudioFile |
| .write(new String(configurationStream.readAllBytes())); |
| Log.i(TAG, "Temporary Car Audio Configuration using Core Audio File Location: " |
| + mTemporaryAudioConfigurationUsingCoreAudioFile.getPath()); |
| } |
| |
| try (InputStream configurationStream = mContext.getResources().openRawResource( |
| R.raw.car_audio_configuration_without_mirroring)) { |
| mTemporaryAudioConfigurationWithoutMirroringFile = new TemporaryFile("xml"); |
| mTemporaryAudioConfigurationWithoutMirroringFile |
| .write(new String(configurationStream.readAllBytes())); |
| Log.i(TAG, "Temporary Car Audio Configuration Without Mirroring File Location: " |
| + mTemporaryAudioConfigurationWithoutMirroringFile.getPath()); |
| } |
| |
| mockCoreAudioRoutingAndVolume(); |
| mockGrantCarControlAudioSettingsPermission(); |
| |
| setupAudioControlHAL(); |
| setupService(); |
| |
| when(Settings.Secure.getUriFor( |
| CarSettings.Secure.KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL)) |
| .thenReturn(mNavSettingUri); |
| } |
| |
| @After |
| public void tearDown() throws Exception { |
| mTemporaryAudioConfigurationFile.close(); |
| mTemporaryAudioConfigurationWithoutZoneMappingFile.close(); |
| CarLocalServices.removeServiceForTest(CarOemProxyService.class); |
| CarLocalServices.removeServiceForTest(CarOccupantZoneService.class); |
| } |
| |
| private void setupAudioControlHAL() { |
| when(mBinder.queryLocalInterface(anyString())).thenReturn(mAudioControl); |
| doReturn(mBinder).when(AudioControlWrapperAidl::getService); |
| when(mAudioControlWrapperAidl.supportsFeature( |
| AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_DUCKING)).thenReturn(true); |
| when(mAudioControlWrapperAidl.supportsFeature( |
| AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_FOCUS)).thenReturn(true); |
| when(mAudioControlWrapperAidl.supportsFeature( |
| AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_GAIN_CALLBACK)).thenReturn(true); |
| when(mAudioControlWrapperAidl.supportsFeature( |
| AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_GROUP_MUTING)).thenReturn(true); |
| when(mAudioControlWrapperAidl.supportsFeature( |
| AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_MODULE_CALLBACK)).thenReturn(true); |
| doReturn(mAudioControlWrapperAidl) |
| .when(() -> AudioControlFactory.newAudioControl()); |
| } |
| |
| private void setupService() throws Exception { |
| when(mMockContext.getSystemService(Context.TELEPHONY_SERVICE)) |
| .thenReturn(mMockTelephonyManager); |
| when(mMockContext.getSystemService(Context.AUDIO_SERVICE)) |
| .thenReturn(mAudioManager); |
| when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager); |
| doReturn(true) |
| .when(() -> AudioManagerHelper |
| .setAudioDeviceGain(any(), any(), anyInt(), anyBoolean())); |
| doReturn(true) |
| .when(() -> SystemProperties.getBoolean(PROPERTY_RO_ENABLE_AUDIO_PATCH, false)); |
| |
| when(mMockOccupantZoneService.getUserForOccupant(TEST_DRIVER_OCCUPANT_ZONE_ID)) |
| .thenReturn(TEST_DRIVER_USER_ID); |
| when(mMockOccupantZoneService.getDriverUserId()).thenReturn(TEST_DRIVER_USER_ID); |
| when(mMockOccupantZoneService.getAudioZoneIdForOccupant(TEST_DRIVER_OCCUPANT_ZONE_ID)) |
| .thenReturn(PRIMARY_AUDIO_ZONE); |
| when(mMockOccupantZoneService.getOccupantZoneForUser(UserHandle.of(TEST_DRIVER_USER_ID))) |
| .thenReturn(TEST_DRIVER_OCCUPANT); |
| |
| when(mMockOccupantZoneService.getUserForOccupant(TEST_REAR_LEFT_OCCUPANT_ZONE_ID)) |
| .thenReturn(TEST_REAR_LEFT_USER_ID); |
| when(mMockOccupantZoneService.getUserForOccupant(TEST_REAR_RIGHT_OCCUPANT_ZONE_ID)) |
| .thenReturn(TEST_REAR_RIGHT_USER_ID); |
| when(mMockOccupantZoneService.getUserForOccupant(TEST_FRONT_OCCUPANT_ZONE_ID)) |
| .thenReturn(TEST_FRONT_PASSEGNER_USER_ID); |
| when(mMockOccupantZoneService.getAudioZoneIdForOccupant(TEST_REAR_LEFT_OCCUPANT_ZONE_ID)) |
| .thenReturn(TEST_REAR_LEFT_ZONE_ID); |
| when(mMockOccupantZoneService.getAudioZoneIdForOccupant(TEST_REAR_RIGHT_OCCUPANT_ZONE_ID)) |
| .thenReturn(TEST_REAR_RIGHT_ZONE_ID); |
| when(mMockOccupantZoneService.getAudioZoneIdForOccupant(TEST_FRONT_OCCUPANT_ZONE_ID)) |
| .thenReturn(TEST_FRONT_PASSEGNER_USER_ID); |
| when(mMockOccupantZoneService.getOccupantZoneForUser( |
| UserHandle.of(TEST_REAR_RIGHT_USER_ID))).thenReturn( |
| TEST_REAR_RIGHT_PASSENGER_OCCUPANT); |
| when(mMockOccupantZoneService.getOccupantZoneForUser( |
| UserHandle.of(TEST_FRONT_PASSEGNER_USER_ID))).thenReturn( |
| TEST_FRONT_PASSENGER_OCCUPANT); |
| when(mMockOccupantZoneService.getOccupantZoneForUser( |
| UserHandle.of(TEST_REAR_LEFT_USER_ID))).thenReturn( |
| TEST_REAR_LEFT_PASSENGER_OCCUPANT); |
| when(mMockOccupantZoneService.getOccupantForAudioZoneId(TEST_REAR_LEFT_ZONE_ID)) |
| .thenReturn(TEST_REAR_LEFT_PASSENGER_OCCUPANT); |
| when(mMockOccupantZoneService.getOccupantForAudioZoneId(TEST_REAR_RIGHT_ZONE_ID)) |
| .thenReturn(TEST_REAR_RIGHT_PASSENGER_OCCUPANT); |
| when(mMockOccupantZoneService.getOccupantForAudioZoneId(TEST_FRONT_ZONE_ID)) |
| .thenReturn(TEST_FRONT_PASSENGER_OCCUPANT); |
| |
| CarLocalServices.removeServiceForTest(CarOccupantZoneService.class); |
| CarLocalServices.addService(CarOccupantZoneService.class, mMockOccupantZoneService); |
| CarLocalServices.removeServiceForTest(CarInputService.class); |
| CarLocalServices.addService(CarInputService.class, mMockCarInputService); |
| |
| CarLocalServices.removeServiceForTest(CarOemProxyService.class); |
| CarLocalServices.addService(CarOemProxyService.class, mMockCarOemProxyService); |
| |
| setupAudioManager(); |
| |
| setupResources(); |
| |
| mCarAudioService = |
| new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| } |
| |
| private void setupAudioManager() throws Exception { |
| AudioDeviceInfo[] outputDevices = generateOutputDeviceInfos(); |
| AudioDeviceInfo[] inputDevices = generateInputDeviceInfos(); |
| when(mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS)) |
| .thenReturn(outputDevices); |
| when(mAudioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)) |
| .thenReturn(inputDevices); |
| when(mMockContext.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mAudioManager); |
| |
| when(mAudioManager.registerAudioPolicy(any())).thenAnswer(invocation -> { |
| AudioPolicy policy = (AudioPolicy) invocation.getArguments()[0]; |
| policy.setRegistration(REGISTRATION_ID); |
| return SUCCESS; |
| }); |
| |
| IBinder mockBinder = mock(IBinder.class); |
| when(mockBinder.queryLocalInterface(any())).thenReturn(mMockAudioService); |
| doReturn(mockBinder).when(() -> ServiceManager.getService(Context.AUDIO_SERVICE)); |
| } |
| |
| private void setupResources() { |
| when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver); |
| when(mMockContext.createContextAsUser(any(), anyInt())).thenReturn(mMockContext); |
| when(mMockContext.getResources()).thenReturn(mMockResources); |
| when(mMockResources.getBoolean(audioUseDynamicRouting)).thenReturn(mUseDynamicRouting); |
| when(mMockResources.getInteger(audioVolumeKeyEventTimeoutMs)) |
| .thenReturn(VOLUME_KEY_EVENT_TIMEOUT_MS); |
| when(mMockResources.getBoolean(audioUseHalDuckingSignals)).thenReturn(mUseHalAudioDucking); |
| when(mMockResources.getBoolean(audioUseCarVolumeGroupMuting)) |
| .thenReturn(mUseCarVolumeGroupMuting); |
| when(mMockResources.getBoolean(audioUseCarVolumeGroupEvent)) |
| .thenReturn(mUseCarVolumeGroupEvents); |
| when(mMockResources.getInteger(audioVolumeAdjustmentContextsVersion)) |
| .thenReturn(AUDIO_CONTEXT_PRIORITY_LIST_VERSION_TWO); |
| when(mMockResources.getBoolean(audioPersistMasterMuteState)).thenReturn(mPersistMasterMute); |
| } |
| |
| @Test |
| public void constructor_withNullContext_fails() { |
| NullPointerException thrown = |
| assertThrows(NullPointerException.class, () -> new CarAudioService(null)); |
| |
| expectWithMessage("Car Audio Service Construction") |
| .that(thrown).hasMessageThat().contains("Context"); |
| } |
| |
| @Test |
| public void constructor_withNullContextAndNullPath_fails() { |
| NullPointerException thrown = |
| assertThrows(NullPointerException.class, |
| () -> new CarAudioService(/* context= */null, |
| /* audioConfigurationPath= */ null, |
| /* carVolumeCallbackHandler= */ null)); |
| |
| expectWithMessage("Car Audio Service Construction") |
| .that(thrown).hasMessageThat().contains("Context"); |
| } |
| |
| @Test |
| public void constructor_withInvalidVolumeConfiguration_fails() { |
| when(mMockResources.getInteger(audioVolumeAdjustmentContextsVersion)) |
| .thenReturn(AUDIO_CONTEXT_PRIORITY_LIST_VERSION_ONE); |
| |
| IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, |
| () -> new CarAudioService(mMockContext)); |
| |
| expectWithMessage("Car Audio Service Construction") |
| .that(thrown).hasMessageThat() |
| .contains("requires audioVolumeAdjustmentContextsVersion 2"); |
| } |
| |
| @Test |
| public void getAudioZoneIds_withBaseConfiguration_returnAllTheZones() { |
| mCarAudioService.init(); |
| |
| expectWithMessage("Car Audio Service Zones") |
| .that(mCarAudioService.getAudioZoneIds()).asList() |
| .containsExactly(PRIMARY_AUDIO_ZONE, TEST_REAR_LEFT_ZONE_ID, |
| TEST_REAR_RIGHT_ZONE_ID, TEST_FRONT_ZONE_ID); |
| } |
| |
| @Test |
| public void getVolumeGroupCount_onPrimaryZone_returnsAllGroups() { |
| mCarAudioService.init(); |
| |
| expectWithMessage("Primary zone car volume group count") |
| .that(mCarAudioService.getVolumeGroupCount(PRIMARY_AUDIO_ZONE)) |
| .isEqualTo(PRIMARY_ZONE_VOLUME_GROUP_COUNT); |
| } |
| |
| @Test |
| public void getVolumeGroupCount_onPrimaryZone__withNonDynamicRouting_returnsAllGroups() { |
| when(mMockResources.getBoolean(audioUseDynamicRouting)) |
| .thenReturn(/* useDynamicRouting= */ false); |
| CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| nonDynamicAudioService.init(); |
| |
| expectWithMessage("Non dynamic routing primary zone car volume group count") |
| .that(nonDynamicAudioService.getVolumeGroupCount(PRIMARY_AUDIO_ZONE)) |
| .isEqualTo(CarAudioDynamicRouting.STREAM_TYPES.length); |
| } |
| |
| @Test |
| public void getVolumeGroupIdForUsage_forMusicUsage() { |
| mCarAudioService.init(); |
| |
| expectWithMessage("Primary zone's media car volume group id") |
| .that(mCarAudioService.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE, USAGE_MEDIA)) |
| .isEqualTo(MEDIA_VOLUME_GROUP_ID); |
| } |
| |
| @Test |
| public void getVolumeGroupIdForUsage_withNonDynamicRouting_forMusicUsage() { |
| when(mMockResources.getBoolean(audioUseDynamicRouting)) |
| .thenReturn(/* useDynamicRouting= */ false); |
| CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| nonDynamicAudioService.init(); |
| |
| expectWithMessage("Non dynamic routing primary zone's media car volume group id") |
| .that(nonDynamicAudioService.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE, |
| USAGE_MEDIA)).isEqualTo(MEDIA_VOLUME_GROUP_ID); |
| } |
| |
| @Test |
| public void getVolumeGroupIdForUsage_forNavigationUsage() { |
| mCarAudioService.init(); |
| |
| expectWithMessage("Primary zone's navigation car volume group id") |
| .that(mCarAudioService.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE, |
| USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)) |
| .isEqualTo(NAVIGATION_VOLUME_GROUP_ID); |
| } |
| |
| @Test |
| public void getVolumeGroupIdForUsage_withNonDynamicRouting_forNavigationUsage() { |
| when(mMockResources.getBoolean(audioUseDynamicRouting)) |
| .thenReturn(/* useDynamicRouting= */ false); |
| CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| nonDynamicAudioService.init(); |
| |
| expectWithMessage("Non dynamic routing primary zone's navigation car volume group id") |
| .that(nonDynamicAudioService.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE, |
| USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)) |
| .isEqualTo(INVALID_VOLUME_GROUP_ID); |
| } |
| |
| @Test |
| public void getVolumeGroupIdForUsage_forInvalidUsage_returnsInvalidGroupId() { |
| mCarAudioService.init(); |
| |
| expectWithMessage("Primary zone's invalid car volume group id") |
| .that(mCarAudioService.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE, INVALID_USAGE)) |
| .isEqualTo(INVALID_VOLUME_GROUP_ID); |
| } |
| |
| @Test |
| public void |
| getVolumeGroupIdForUsage_forInvalidUsage_withNonDynamicRouting_returnsInvalidGroupId() { |
| when(mMockResources.getBoolean(audioUseDynamicRouting)) |
| .thenReturn(/* useDynamicRouting= */ false); |
| CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| nonDynamicAudioService.init(); |
| |
| expectWithMessage("Non dynamic routing primary zone's invalid car volume group id") |
| .that(nonDynamicAudioService.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE, |
| INVALID_USAGE)).isEqualTo(INVALID_VOLUME_GROUP_ID); |
| } |
| |
| @Test |
| public void getVolumeGroupIdForUsage_forUnknownUsage_returnsMediaGroupId() { |
| mCarAudioService.init(); |
| |
| expectWithMessage("Primary zone's unknown car volume group id") |
| .that(mCarAudioService.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE, USAGE_UNKNOWN)) |
| .isEqualTo(MEDIA_VOLUME_GROUP_ID); |
| } |
| |
| @Test |
| public void getVolumeGroupIdForUsage_forVirtualUsage_returnsInvalidGroupId() { |
| mCarAudioService.init(); |
| |
| expectWithMessage("Primary zone's virtual car volume group id") |
| .that(mCarAudioService.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE, |
| AudioManagerHelper.getUsageVirtualSource())) |
| .isEqualTo(INVALID_VOLUME_GROUP_ID); |
| } |
| |
| @Test |
| public void getVolumeGroupCount_onSecondaryZone_returnsAllGroups() { |
| mCarAudioService.init(); |
| |
| expectWithMessage("Secondary Zone car volume group count") |
| .that(mCarAudioService.getVolumeGroupCount(TEST_REAR_LEFT_ZONE_ID)) |
| .isEqualTo(SECONDARY_ZONE_VOLUME_GROUP_COUNT); |
| } |
| |
| @Test |
| public void getUsagesForVolumeGroupId_forMusicContext() { |
| mCarAudioService.init(); |
| |
| |
| expectWithMessage("Primary zone's music car volume group id usages") |
| .that(mCarAudioService.getUsagesForVolumeGroupId(PRIMARY_AUDIO_ZONE, |
| MEDIA_VOLUME_GROUP_ID)).asList() |
| .containsExactly(USAGE_UNKNOWN, USAGE_GAME, USAGE_MEDIA, USAGE_ANNOUNCEMENT, |
| USAGE_NOTIFICATION, USAGE_NOTIFICATION_EVENT); |
| } |
| |
| @Test |
| public void getUsagesForVolumeGroupId_forSystemContext() { |
| mCarAudioService.init(); |
| int systemVolumeGroup = |
| mCarAudioService.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE, USAGE_EMERGENCY); |
| |
| expectWithMessage("Primary zone's system car volume group id usages") |
| .that(mCarAudioService.getUsagesForVolumeGroupId(PRIMARY_AUDIO_ZONE, |
| systemVolumeGroup)).asList().containsExactly(USAGE_ALARM, USAGE_EMERGENCY, |
| USAGE_SAFETY, USAGE_VEHICLE_STATUS, USAGE_ASSISTANCE_SONIFICATION); |
| } |
| |
| @Test |
| public void getUsagesForVolumeGroupId_onSecondaryZone_forSingleVolumeGroupId_returnAllUsages() { |
| mCarAudioService.init(); |
| |
| expectWithMessage("Secondary Zone's car volume group id usages") |
| .that(mCarAudioService.getUsagesForVolumeGroupId(TEST_REAR_LEFT_ZONE_ID, |
| SECONDARY_ZONE_VOLUME_GROUP_ID)) |
| .asList().containsExactly(USAGE_UNKNOWN, USAGE_MEDIA, |
| USAGE_VOICE_COMMUNICATION, USAGE_VOICE_COMMUNICATION_SIGNALLING, |
| USAGE_ALARM, USAGE_NOTIFICATION, USAGE_NOTIFICATION_RINGTONE, |
| USAGE_NOTIFICATION_EVENT, USAGE_ASSISTANCE_ACCESSIBILITY, |
| USAGE_ASSISTANCE_NAVIGATION_GUIDANCE, USAGE_ASSISTANCE_SONIFICATION, |
| USAGE_GAME, USAGE_ASSISTANT, USAGE_CALL_ASSISTANT, USAGE_EMERGENCY, |
| USAGE_ANNOUNCEMENT, USAGE_SAFETY, USAGE_VEHICLE_STATUS); |
| } |
| |
| @Test |
| public void getUsagesForVolumeGroupId_withoutDynamicRouting() { |
| when(mMockResources.getBoolean(audioUseDynamicRouting)) |
| .thenReturn(/* useDynamicRouting= */ false); |
| CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| nonDynamicAudioService.init(); |
| |
| expectWithMessage("Media car volume group id without dynamic routing").that( |
| nonDynamicAudioService.getUsagesForVolumeGroupId(PRIMARY_AUDIO_ZONE, |
| MEDIA_VOLUME_GROUP_ID)).asList() |
| .containsExactly(CarAudioDynamicRouting.STREAM_TYPE_USAGES[MEDIA_VOLUME_GROUP_ID]); |
| } |
| |
| @Test |
| public void createAudioPatch_onMediaOutputDevice_failsForConfigurationMissing() { |
| mCarAudioService.init(); |
| |
| doReturn(false) |
| .when(() -> SystemProperties.getBoolean(PROPERTY_RO_ENABLE_AUDIO_PATCH, false)); |
| |
| IllegalStateException thrown = assertThrows(IllegalStateException.class, |
| () -> mCarAudioService |
| .createAudioPatch(PRIMARY_ZONE_FM_TUNER_ADDRESS, |
| USAGE_MEDIA, DEFAULT_GAIN)); |
| |
| expectWithMessage("FM and Media Audio Patch Exception") |
| .that(thrown).hasMessageThat().contains("Audio Patch APIs not enabled"); |
| } |
| |
| @Test |
| public void createAudioPatch_onMediaOutputDevice_failsForMissingPermission() { |
| mCarAudioService.init(); |
| |
| mockDenyCarControlAudioSettingsPermission(); |
| |
| SecurityException thrown = assertThrows(SecurityException.class, |
| () -> mCarAudioService |
| .createAudioPatch(PRIMARY_ZONE_FM_TUNER_ADDRESS, |
| USAGE_MEDIA, DEFAULT_GAIN)); |
| |
| expectWithMessage("FM and Media Audio Patch Permission Exception") |
| .that(thrown).hasMessageThat().contains(PERMISSION_CAR_CONTROL_AUDIO_SETTINGS); |
| } |
| |
| @Test |
| public void createAudioPatch_onMediaOutputDevice_succeeds() { |
| mCarAudioService.init(); |
| |
| mockGrantCarControlAudioSettingsPermission(); |
| doReturn(false) |
| .when(() -> SystemProperties.getBoolean(PROPERTY_RO_ENABLE_AUDIO_PATCH, true)); |
| doReturn(new AudioPatchInfo(PRIMARY_ZONE_FM_TUNER_ADDRESS, MEDIA_TEST_DEVICE, 0)) |
| .when(() -> AudioManagerHelper |
| .createAudioPatch(mFmTunerInputDevice, mMediaOutputDevice, DEFAULT_GAIN)); |
| |
| CarAudioPatchHandle audioPatch = mCarAudioService |
| .createAudioPatch(PRIMARY_ZONE_FM_TUNER_ADDRESS, USAGE_MEDIA, DEFAULT_GAIN); |
| |
| expectWithMessage("Audio Patch Sink Address") |
| .that(audioPatch.getSinkAddress()).isEqualTo(MEDIA_TEST_DEVICE); |
| expectWithMessage("Audio Patch Source Address") |
| .that(audioPatch.getSourceAddress()).isEqualTo(PRIMARY_ZONE_FM_TUNER_ADDRESS); |
| expectWithMessage("Audio Patch Handle") |
| .that(audioPatch.getHandleId()).isEqualTo(0); |
| } |
| |
| @Test |
| public void releaseAudioPatch_failsForConfigurationMissing() { |
| mCarAudioService.init(); |
| |
| doReturn(false) |
| .when(() -> SystemProperties.getBoolean(PROPERTY_RO_ENABLE_AUDIO_PATCH, false)); |
| CarAudioPatchHandle carAudioPatchHandle = |
| new CarAudioPatchHandle(0, PRIMARY_ZONE_FM_TUNER_ADDRESS, MEDIA_TEST_DEVICE); |
| |
| IllegalStateException thrown = assertThrows(IllegalStateException.class, |
| () -> mCarAudioService.releaseAudioPatch(carAudioPatchHandle)); |
| |
| expectWithMessage("Release FM and Media Audio Patch Exception") |
| .that(thrown).hasMessageThat().contains("Audio Patch APIs not enabled"); |
| } |
| |
| @Test |
| public void releaseAudioPatch_failsForMissingPermission() { |
| mCarAudioService.init(); |
| |
| mockDenyCarControlAudioSettingsPermission(); |
| CarAudioPatchHandle carAudioPatchHandle = |
| new CarAudioPatchHandle(0, PRIMARY_ZONE_FM_TUNER_ADDRESS, MEDIA_TEST_DEVICE); |
| |
| SecurityException thrown = assertThrows(SecurityException.class, |
| () -> mCarAudioService.releaseAudioPatch(carAudioPatchHandle)); |
| |
| expectWithMessage("FM and Media Audio Patch Permission Exception") |
| .that(thrown).hasMessageThat().contains(PERMISSION_CAR_CONTROL_AUDIO_SETTINGS); |
| } |
| |
| @Test |
| public void releaseAudioPatch_forNullSourceAddress_throwsNullPointerException() { |
| mCarAudioService.init(); |
| mockGrantCarControlAudioSettingsPermission(); |
| doReturn(new AudioPatchInfo(PRIMARY_ZONE_FM_TUNER_ADDRESS, MEDIA_TEST_DEVICE, 0)) |
| .when(() -> AudioManagerHelper |
| .createAudioPatch(mFmTunerInputDevice, mMediaOutputDevice, DEFAULT_GAIN)); |
| |
| CarAudioPatchHandle audioPatch = mock(CarAudioPatchHandle.class); |
| when(audioPatch.getSourceAddress()).thenReturn(null); |
| |
| NullPointerException thrown = assertThrows(NullPointerException.class, |
| () -> mCarAudioService.releaseAudioPatch(audioPatch)); |
| |
| expectWithMessage("Release audio patch for null source address " |
| + "and sink address Null Exception") |
| .that(thrown).hasMessageThat() |
| .contains("Source Address can not be null for patch id 0"); |
| } |
| |
| @Test |
| public void releaseAudioPatch_failsForNullPatch() { |
| mCarAudioService.init(); |
| |
| assertThrows(NullPointerException.class, |
| () -> mCarAudioService.releaseAudioPatch(null)); |
| } |
| |
| @Test |
| public void setZoneIdForUid_withoutRoutingPermission_fails() { |
| mCarAudioService.init(); |
| |
| mockDenyCarControlAudioSettingsPermission(); |
| |
| SecurityException thrown = assertThrows(SecurityException.class, |
| () -> mCarAudioService.setZoneIdForUid(OUT_OF_RANGE_ZONE, MEDIA_APP_UID)); |
| |
| expectWithMessage("Set Zone for UID Permission Exception") |
| .that(thrown).hasMessageThat() |
| .contains(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS); |
| } |
| |
| @Test |
| public void setZoneIdForUid_withoutDynamicRouting_fails() { |
| when(mMockResources.getBoolean(audioUseDynamicRouting)) |
| .thenReturn(/* useDynamicRouting= */ false); |
| CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| nonDynamicAudioService.init(); |
| |
| IllegalStateException thrown = assertThrows(IllegalStateException.class, |
| () -> nonDynamicAudioService.setZoneIdForUid(PRIMARY_AUDIO_ZONE, MEDIA_APP_UID)); |
| |
| expectWithMessage("Set Zone for UID Dynamic Configuration Exception") |
| .that(thrown).hasMessageThat() |
| .contains("Dynamic routing is required"); |
| } |
| |
| @Test |
| public void setZoneIdForUid_withInvalidZone_fails() { |
| mCarAudioService.init(); |
| |
| IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, |
| () -> mCarAudioService.setZoneIdForUid(INVALID_AUDIO_ZONE, MEDIA_APP_UID)); |
| |
| expectWithMessage("Set Zone for UID Invalid Zone Exception") |
| .that(thrown).hasMessageThat() |
| .contains("Invalid audio zone Id " + INVALID_AUDIO_ZONE); |
| } |
| |
| @Test |
| public void setZoneIdForUid_withOutOfRangeZone_fails() { |
| mCarAudioService.init(); |
| |
| IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, |
| () -> mCarAudioService.setZoneIdForUid(OUT_OF_RANGE_ZONE, MEDIA_APP_UID)); |
| |
| expectWithMessage("Set Zone for UID Zone Out of Range Exception") |
| .that(thrown).hasMessageThat() |
| .contains("Invalid audio zone Id " + OUT_OF_RANGE_ZONE); |
| } |
| |
| @Test |
| public void setZoneIdForUid_withZoneAudioMapping_fails() { |
| mCarAudioService.init(); |
| |
| IllegalStateException thrown = assertThrows(IllegalStateException.class, |
| () -> mCarAudioService.setZoneIdForUid(PRIMARY_AUDIO_ZONE, MEDIA_APP_UID)); |
| |
| expectWithMessage("Set Zone for UID With Audio Zone Mapping Exception") |
| .that(thrown).hasMessageThat() |
| .contains("UID based routing is not supported while using occupant zone mapping"); |
| } |
| |
| @Test |
| public void setZoneIdForUid_withValidZone_succeeds() throws Exception { |
| when(mMockAudioService.setUidDeviceAffinity(any(), anyInt(), any(), any())) |
| .thenReturn(SUCCESS); |
| CarAudioService noZoneMappingAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| noZoneMappingAudioService.init(); |
| |
| boolean results = noZoneMappingAudioService |
| .setZoneIdForUid(TEST_REAR_LEFT_ZONE_ID, MEDIA_APP_UID); |
| |
| expectWithMessage("Set Zone for UID Status").that(results).isTrue(); |
| } |
| |
| @Test |
| public void setZoneIdForUid_onDifferentZones_succeeds() throws Exception { |
| when(mMockAudioService.setUidDeviceAffinity(any(), anyInt(), any(), any())) |
| .thenReturn(SUCCESS); |
| CarAudioService noZoneMappingAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| noZoneMappingAudioService.init(); |
| |
| noZoneMappingAudioService |
| .setZoneIdForUid(TEST_REAR_LEFT_ZONE_ID, MEDIA_APP_UID); |
| |
| boolean results = noZoneMappingAudioService |
| .setZoneIdForUid(PRIMARY_AUDIO_ZONE, MEDIA_APP_UID); |
| |
| expectWithMessage("Set Zone for UID For Different Zone") |
| .that(results).isTrue(); |
| } |
| |
| @Test |
| public void setZoneIdForUid_onDifferentZones_withAudioFocus_succeeds() throws Exception { |
| when(mMockAudioService.setUidDeviceAffinity(any(), anyInt(), any(), any())) |
| .thenReturn(SUCCESS); |
| CarAudioService noZoneMappingAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| noZoneMappingAudioService.init(); |
| AudioFocusInfo audioFocusInfo = createAudioFocusInfoForMedia(); |
| |
| noZoneMappingAudioService |
| .setZoneIdForUid(TEST_REAR_LEFT_ZONE_ID, MEDIA_APP_UID); |
| |
| noZoneMappingAudioService |
| .requestAudioFocusForTest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED); |
| |
| boolean results = noZoneMappingAudioService |
| .setZoneIdForUid(PRIMARY_AUDIO_ZONE, MEDIA_APP_UID); |
| |
| expectWithMessage("Set Zone for UID For Different Zone with Audio Focus") |
| .that(results).isTrue(); |
| } |
| |
| @Test |
| public void getZoneIdForUid_withoutMappedUid_succeeds() throws Exception { |
| when(mMockAudioService.setUidDeviceAffinity(any(), anyInt(), any(), any())) |
| .thenReturn(SUCCESS); |
| CarAudioService noZoneMappingAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| noZoneMappingAudioService.init(); |
| |
| int zoneId = noZoneMappingAudioService |
| .getZoneIdForUid(MEDIA_APP_UID); |
| |
| expectWithMessage("Get Zone for Non Mapped UID") |
| .that(zoneId).isEqualTo(PRIMARY_AUDIO_ZONE); |
| } |
| |
| @Test |
| public void getZoneIdForUid_succeeds() throws Exception { |
| when(mMockAudioService.setUidDeviceAffinity(any(), anyInt(), any(), any())) |
| .thenReturn(SUCCESS); |
| CarAudioService noZoneMappingAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| noZoneMappingAudioService.init(); |
| |
| noZoneMappingAudioService |
| .setZoneIdForUid(TEST_REAR_LEFT_ZONE_ID, MEDIA_APP_UID); |
| |
| int zoneId = noZoneMappingAudioService |
| .getZoneIdForUid(MEDIA_APP_UID); |
| |
| expectWithMessage("Get Zone for UID Zone Id") |
| .that(zoneId).isEqualTo(TEST_REAR_LEFT_ZONE_ID); |
| } |
| |
| @Test |
| public void getZoneIdForUid_afterSwitchingZones_succeeds() throws Exception { |
| when(mMockAudioService.setUidDeviceAffinity(any(), anyInt(), any(), any())) |
| .thenReturn(SUCCESS); |
| CarAudioService noZoneMappingAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| noZoneMappingAudioService.init(); |
| |
| noZoneMappingAudioService |
| .setZoneIdForUid(TEST_REAR_LEFT_ZONE_ID, MEDIA_APP_UID); |
| |
| noZoneMappingAudioService |
| .setZoneIdForUid(PRIMARY_AUDIO_ZONE, MEDIA_APP_UID); |
| |
| int zoneId = noZoneMappingAudioService |
| .getZoneIdForUid(MEDIA_APP_UID); |
| |
| expectWithMessage("Get Zone for UID Zone Id") |
| .that(zoneId).isEqualTo(PRIMARY_AUDIO_ZONE); |
| } |
| |
| @Test |
| public void clearZoneIdForUid_withoutRoutingPermission_fails() { |
| mCarAudioService.init(); |
| |
| mockDenyCarControlAudioSettingsPermission(); |
| |
| SecurityException thrown = assertThrows(SecurityException.class, |
| () -> mCarAudioService.clearZoneIdForUid(MEDIA_APP_UID)); |
| |
| expectWithMessage("Clear Zone for UID Permission Exception") |
| .that(thrown).hasMessageThat() |
| .contains(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS); |
| } |
| |
| @Test |
| public void clearZoneIdForUid_withoutDynamicRouting_fails() { |
| when(mMockResources.getBoolean(audioUseDynamicRouting)) |
| .thenReturn(/* useDynamicRouting= */ false); |
| CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| nonDynamicAudioService.init(); |
| |
| IllegalStateException thrown = assertThrows(IllegalStateException.class, |
| () -> nonDynamicAudioService.clearZoneIdForUid(MEDIA_APP_UID)); |
| |
| expectWithMessage("Clear Zone for UID Dynamic Configuration Exception") |
| .that(thrown).hasMessageThat() |
| .contains("Dynamic routing is required"); |
| } |
| |
| @Test |
| public void clearZoneIdForUid_withZoneAudioMapping_fails() { |
| mCarAudioService.init(); |
| |
| IllegalStateException thrown = assertThrows(IllegalStateException.class, |
| () -> mCarAudioService.clearZoneIdForUid(MEDIA_APP_UID)); |
| |
| expectWithMessage("Clear Zone for UID Audio Zone Mapping Exception") |
| .that(thrown).hasMessageThat() |
| .contains("UID based routing is not supported while using occupant zone mapping"); |
| } |
| |
| @Test |
| public void clearZoneIdForUid_forNonMappedUid_succeeds() throws Exception { |
| CarAudioService noZoneMappingAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| noZoneMappingAudioService.init(); |
| |
| boolean status = noZoneMappingAudioService |
| .clearZoneIdForUid(MEDIA_APP_UID); |
| |
| expectWithMessage("Clear Zone for UID Audio Zone without Mapping") |
| .that(status).isTrue(); |
| } |
| |
| @Test |
| public void clearZoneIdForUid_forMappedUid_succeeds() throws Exception { |
| when(mMockAudioService.setUidDeviceAffinity(any(), anyInt(), any(), any())) |
| .thenReturn(SUCCESS); |
| CarAudioService noZoneMappingAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| noZoneMappingAudioService.init(); |
| |
| noZoneMappingAudioService |
| .setZoneIdForUid(TEST_REAR_LEFT_ZONE_ID, MEDIA_APP_UID); |
| |
| boolean status = noZoneMappingAudioService.clearZoneIdForUid(MEDIA_APP_UID); |
| |
| expectWithMessage("Clear Zone for UID Audio Zone with Mapping") |
| .that(status).isTrue(); |
| } |
| |
| @Test |
| public void getZoneIdForUid_afterClearedUidMapping_returnsDefaultZone() throws Exception { |
| when(mMockAudioService.setUidDeviceAffinity(any(), anyInt(), any(), any())) |
| .thenReturn(SUCCESS); |
| CarAudioService noZoneMappingAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| noZoneMappingAudioService.init(); |
| |
| noZoneMappingAudioService |
| .setZoneIdForUid(TEST_REAR_LEFT_ZONE_ID, MEDIA_APP_UID); |
| |
| noZoneMappingAudioService.clearZoneIdForUid(MEDIA_APP_UID); |
| |
| int zoneId = noZoneMappingAudioService.getZoneIdForUid(MEDIA_APP_UID); |
| |
| expectWithMessage("Get Zone for UID Audio Zone with Cleared Mapping") |
| .that(zoneId).isEqualTo(PRIMARY_AUDIO_ZONE); |
| } |
| |
| @Test |
| public void getZoneIdForAudioFocusInfo_withoutMappedUid_succeeds() throws Exception { |
| when(mMockAudioService.setUidDeviceAffinity(any(), anyInt(), any(), any())) |
| .thenReturn(SUCCESS); |
| CarAudioService noZoneMappingAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| noZoneMappingAudioService.init(); |
| |
| int zoneId = noZoneMappingAudioService |
| .getZoneIdForAudioFocusInfo(TEST_AUDIO_FOCUS_INFO); |
| |
| expectWithMessage("Mapped audio focus info's zone") |
| .that(zoneId).isEqualTo(PRIMARY_AUDIO_ZONE); |
| } |
| |
| @Test |
| public void getZoneIdForAudioFocusInfo_succeeds() throws Exception { |
| when(mMockAudioService.setUidDeviceAffinity(any(), anyInt(), any(), any())) |
| .thenReturn(SUCCESS); |
| CarAudioService noZoneMappingAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| noZoneMappingAudioService.init(); |
| |
| noZoneMappingAudioService |
| .setZoneIdForUid(TEST_REAR_LEFT_ZONE_ID, MEDIA_APP_UID); |
| |
| int zoneId = noZoneMappingAudioService |
| .getZoneIdForAudioFocusInfo(TEST_AUDIO_FOCUS_INFO); |
| |
| expectWithMessage("Mapped audio focus info's zone") |
| .that(zoneId).isEqualTo(TEST_REAR_LEFT_ZONE_ID); |
| } |
| |
| @Test |
| public void getZoneIdForAudioFocusInfo_afterSwitchingZones_succeeds() throws Exception { |
| when(mMockAudioService.setUidDeviceAffinity(any(), anyInt(), any(), any())) |
| .thenReturn(SUCCESS); |
| CarAudioService noZoneMappingAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| noZoneMappingAudioService.init(); |
| noZoneMappingAudioService |
| .setZoneIdForUid(TEST_REAR_LEFT_ZONE_ID, MEDIA_APP_UID); |
| noZoneMappingAudioService |
| .setZoneIdForUid(PRIMARY_AUDIO_ZONE, MEDIA_APP_UID); |
| |
| int zoneId = noZoneMappingAudioService |
| .getZoneIdForAudioFocusInfo(TEST_AUDIO_FOCUS_INFO); |
| |
| expectWithMessage("Remapped audio focus info's zone") |
| .that(zoneId).isEqualTo(PRIMARY_AUDIO_ZONE); |
| } |
| |
| @Test |
| public void setGroupVolume_withoutPermission_fails() { |
| mCarAudioService.init(); |
| |
| mockDenyCarControlAudioVolumePermission(); |
| |
| SecurityException thrown = assertThrows(SecurityException.class, |
| () -> mCarAudioService.setGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP, |
| TEST_GAIN_INDEX, TEST_FLAGS)); |
| |
| expectWithMessage("Set Volume Group Permission Exception") |
| .that(thrown).hasMessageThat() |
| .contains(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME); |
| } |
| |
| @Test |
| public void setGroupVolume_withDynamicRoutingDisabled() { |
| when(mMockResources.getBoolean(audioUseDynamicRouting)) |
| .thenReturn(/* useDynamicRouting= */ false); |
| CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| nonDynamicAudioService.init(); |
| |
| nonDynamicAudioService.setGroupVolume( |
| PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP, TEST_GAIN_INDEX, TEST_FLAGS); |
| |
| verify(mAudioManager).setStreamVolume( |
| CarAudioDynamicRouting.STREAM_TYPES[TEST_PRIMARY_GROUP], |
| TEST_GAIN_INDEX, |
| TEST_FLAGS); |
| } |
| |
| @Test |
| public void setGroupVolume_verifyNoCallbacks() { |
| mCarAudioService.init(); |
| mCarAudioService.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP, |
| /* mute= */ false, TEST_FLAGS); |
| reset(mCarVolumeCallbackHandler); |
| |
| mCarAudioService.setGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP, TEST_GAIN_INDEX, |
| TEST_FLAGS); |
| |
| verify(mCarVolumeCallbackHandler, never()).onGroupMuteChange(anyInt(), anyInt(), anyInt()); |
| } |
| |
| @Test |
| public void setGroupVolume_afterSetVolumeGroupMute() { |
| mCarAudioService.init(); |
| mCarAudioService.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP, |
| /* mute= */ true, TEST_FLAGS); |
| reset(mCarVolumeCallbackHandler); |
| |
| mCarAudioService.setGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP, TEST_GAIN_INDEX, |
| TEST_FLAGS); |
| |
| verify(mCarVolumeCallbackHandler).onGroupMuteChange(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP, |
| TEST_FLAGS); |
| } |
| |
| @Test |
| public void getOutputDeviceAddressForUsage_forMusicUsage() { |
| mCarAudioService.init(); |
| |
| String mediaDeviceAddress = |
| mCarAudioService.getOutputDeviceAddressForUsage(PRIMARY_AUDIO_ZONE, USAGE_MEDIA); |
| |
| expectWithMessage("Media usage audio device address") |
| .that(mediaDeviceAddress).isEqualTo(MEDIA_TEST_DEVICE); |
| } |
| |
| @Test |
| public void getOutputDeviceAddressForUsage_withNonDynamicRouting_forMediaUsage_fails() { |
| when(mMockResources.getBoolean(audioUseDynamicRouting)) |
| .thenReturn(/* useDynamicRouting= */ false); |
| CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| nonDynamicAudioService.init(); |
| |
| IllegalStateException thrown = assertThrows(IllegalStateException.class, |
| () -> nonDynamicAudioService |
| .getOutputDeviceAddressForUsage(PRIMARY_AUDIO_ZONE, USAGE_MEDIA)); |
| |
| expectWithMessage("Non dynamic routing media usage audio device address exception") |
| .that(thrown).hasMessageThat().contains("Dynamic routing is required"); |
| } |
| |
| @Test |
| public void getOutputDeviceAddressForUsage_forNavigationUsage() { |
| mCarAudioService.init(); |
| |
| String mediaDeviceAddress = |
| mCarAudioService.getOutputDeviceAddressForUsage(PRIMARY_AUDIO_ZONE, |
| USAGE_ASSISTANCE_NAVIGATION_GUIDANCE); |
| |
| expectWithMessage("Navigation usage audio device address") |
| .that(mediaDeviceAddress).isEqualTo(NAVIGATION_TEST_DEVICE); |
| } |
| |
| @Test |
| public void getOutputDeviceAddressForUsage_forInvalidUsage_fails() { |
| mCarAudioService.init(); |
| |
| IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> |
| mCarAudioService.getOutputDeviceAddressForUsage(PRIMARY_AUDIO_ZONE, |
| INVALID_USAGE)); |
| |
| expectWithMessage("Invalid usage audio device address exception") |
| .that(thrown).hasMessageThat().contains("Invalid audio attribute " + INVALID_USAGE); |
| } |
| |
| @Test |
| public void getOutputDeviceAddressForUsage_forVirtualUsage_fails() { |
| mCarAudioService.init(); |
| |
| IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> |
| mCarAudioService.getOutputDeviceAddressForUsage(PRIMARY_AUDIO_ZONE, |
| AudioManagerHelper.getUsageVirtualSource())); |
| |
| expectWithMessage("Invalid context audio device address exception") |
| .that(thrown).hasMessageThat() |
| .contains("invalid"); |
| } |
| |
| @Test |
| public void getOutputDeviceAddressForUsage_onSecondaryZone_forMusicUsage() { |
| mCarAudioService.init(); |
| |
| String mediaDeviceAddress = mCarAudioService.getOutputDeviceAddressForUsage( |
| TEST_REAR_LEFT_ZONE_ID, USAGE_MEDIA); |
| |
| expectWithMessage("Media usage audio device address for secondary zone") |
| .that(mediaDeviceAddress).isEqualTo(SECONDARY_TEST_DEVICE_1); |
| } |
| |
| @Test |
| public void getSuggestedAudioContextForZone_inPrimaryZone() { |
| mCarAudioService.init(); |
| int defaultAudioContext = mCarAudioService.getCarAudioContext() |
| .getContextForAudioAttribute(CAR_DEFAULT_AUDIO_ATTRIBUTE); |
| |
| expectWithMessage("Suggested audio context for primary zone") |
| .that(mCarAudioService.getSuggestedAudioContextForZone(PRIMARY_AUDIO_ZONE)) |
| .isEqualTo(defaultAudioContext); |
| } |
| |
| @Test |
| public void getSuggestedAudioContextForZone_inSecondaryZone() { |
| mCarAudioService.init(); |
| int defaultAudioContext = mCarAudioService.getCarAudioContext() |
| .getContextForAudioAttribute(CAR_DEFAULT_AUDIO_ATTRIBUTE); |
| |
| expectWithMessage("Suggested audio context for secondary zone") |
| .that(mCarAudioService.getSuggestedAudioContextForZone(TEST_REAR_LEFT_ZONE_ID)) |
| .isEqualTo(defaultAudioContext); |
| } |
| |
| @Test |
| public void getSuggestedAudioContextForZone_inInvalidZone() { |
| mCarAudioService.init(); |
| |
| expectWithMessage("Suggested audio context for invalid zone") |
| .that(mCarAudioService.getSuggestedAudioContextForZone(INVALID_AUDIO_ZONE)) |
| .isEqualTo(CarAudioContext.getInvalidContext()); |
| } |
| |
| @Test |
| public void isVolumeGroupMuted_noSetVolumeGroupMute() { |
| mCarAudioService.init(); |
| |
| expectWithMessage("Volume group mute for default state") |
| .that(mCarAudioService.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP)) |
| .isFalse(); |
| } |
| |
| @Test |
| public void isVolumeGroupMuted_setVolumeGroupMuted_isFalse() { |
| mCarAudioService.init(); |
| mCarAudioService.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP, |
| /* mute= */ true, TEST_FLAGS); |
| |
| mCarAudioService.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP, |
| /* mute= */ false, TEST_FLAGS); |
| |
| expectWithMessage("Volume group muted after mute and unmute") |
| .that(mCarAudioService.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP)) |
| .isFalse(); |
| } |
| |
| @Test |
| public void isVolumeGroupMuted_setVolumeGroupMuted_isTrue() { |
| mCarAudioService.init(); |
| |
| mCarAudioService.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP, |
| /* mute= */ true, TEST_FLAGS); |
| expectWithMessage("Volume group muted after mute") |
| .that(mCarAudioService.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP)) |
| .isTrue(); |
| } |
| |
| @Test |
| public void isVolumeGroupMuted_withVolumeGroupMutingDisabled() { |
| when(mMockResources.getBoolean(audioUseCarVolumeGroupMuting)) |
| .thenReturn(false); |
| CarAudioService nonVolumeGroupMutingAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| nonVolumeGroupMutingAudioService.init(); |
| |
| expectWithMessage("Volume group for disabled volume group muting") |
| .that(nonVolumeGroupMutingAudioService.isVolumeGroupMuted( |
| PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP)) |
| .isFalse(); |
| } |
| |
| @Test |
| public void getGroupMaxVolume_forPrimaryZone() { |
| mCarAudioService.init(); |
| |
| expectWithMessage("Group max volume for primary audio zone and group") |
| .that(mCarAudioService.getGroupMaxVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP)) |
| .isEqualTo((MAX_GAIN - MIN_GAIN) / STEP_SIZE); |
| } |
| |
| @Test |
| public void getGroupMinVolume_forPrimaryZone() { |
| mCarAudioService.init(); |
| |
| expectWithMessage("Group Min Volume for primary audio zone and group") |
| .that(mCarAudioService.getGroupMinVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP)) |
| .isEqualTo(0); |
| } |
| |
| @Test |
| public void getGroupCurrentVolume_forPrimaryZone() { |
| mCarAudioService.init(); |
| |
| expectWithMessage("Current group volume for primary audio zone and group") |
| .that(mCarAudioService.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP)) |
| .isEqualTo((DEFAULT_GAIN - MIN_GAIN) / STEP_SIZE); |
| } |
| |
| @Test |
| public void getGroupMaxVolume_withNoDynamicRouting() { |
| when(mMockResources.getBoolean(audioUseDynamicRouting)) |
| .thenReturn(/* useDynamicRouting= */ false); |
| CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| nonDynamicAudioService.init(); |
| |
| nonDynamicAudioService.getGroupMaxVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP); |
| |
| verify(mAudioManager).getStreamMaxVolume( |
| CarAudioDynamicRouting.STREAM_TYPES[TEST_PRIMARY_GROUP]); |
| } |
| |
| @Test |
| public void getGroupMinVolume_withNoDynamicRouting() { |
| when(mMockResources.getBoolean(audioUseDynamicRouting)) |
| .thenReturn(/* useDynamicRouting= */ false); |
| CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| nonDynamicAudioService.init(); |
| |
| nonDynamicAudioService.getGroupMinVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP); |
| |
| verify(mAudioManager).getStreamMinVolume( |
| CarAudioDynamicRouting.STREAM_TYPES[TEST_PRIMARY_GROUP]); |
| } |
| |
| @Test |
| public void getGroupCurrentVolume_withNoDynamicRouting() { |
| when(mMockResources.getBoolean(audioUseDynamicRouting)) |
| .thenReturn(/* useDynamicRouting= */ false); |
| CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| nonDynamicAudioService.init(); |
| |
| nonDynamicAudioService.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP); |
| |
| verify(mAudioManager).getStreamVolume( |
| CarAudioDynamicRouting.STREAM_TYPES[TEST_PRIMARY_GROUP]); |
| } |
| |
| @Test |
| public void setBalanceTowardRight_nonNullValue() { |
| mCarAudioService.init(); |
| |
| mCarAudioService.setBalanceTowardRight(TEST_VALUE); |
| |
| verify(mAudioControlWrapperAidl).setBalanceTowardRight(TEST_VALUE); |
| } |
| |
| @Test |
| public void setBalanceTowardRight_throws() { |
| mCarAudioService.init(); |
| |
| IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () |
| -> mCarAudioService.setBalanceTowardRight(INVALID_TEST_VALUE)); |
| |
| expectWithMessage("Out of bounds balance") |
| .that(thrown).hasMessageThat() |
| .contains(String.format("Balance is out of range of [%f, %f]", -1f, 1f)); |
| } |
| |
| @Test |
| public void setFadeTowardFront_nonNullValue() { |
| mCarAudioService.init(); |
| |
| mCarAudioService.setFadeTowardFront(TEST_VALUE); |
| |
| verify(mAudioControlWrapperAidl).setFadeTowardFront(TEST_VALUE); |
| } |
| |
| @Test |
| public void setFadeTowardFront_throws() { |
| mCarAudioService.init(); |
| |
| IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () |
| -> mCarAudioService.setFadeTowardFront(INVALID_TEST_VALUE)); |
| |
| expectWithMessage("Out of bounds fade") |
| .that(thrown).hasMessageThat() |
| .contains(String.format("Fade is out of range of [%f, %f]", -1f, 1f)); |
| } |
| |
| @Test |
| public void isAudioFeatureEnabled_forDynamicRouting() { |
| mCarAudioService.init(); |
| |
| expectWithMessage("Dynamic routing audio feature") |
| .that(mCarAudioService.isAudioFeatureEnabled(AUDIO_FEATURE_DYNAMIC_ROUTING)) |
| .isEqualTo(mUseDynamicRouting); |
| } |
| |
| @Test |
| public void isAudioFeatureEnabled_forDisabledDynamicRouting() { |
| when(mMockResources.getBoolean(audioUseDynamicRouting)) |
| .thenReturn(/* useDynamicRouting= */ false); |
| CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| nonDynamicAudioService.init(); |
| |
| expectWithMessage("Disabled dynamic routing audio feature") |
| .that(nonDynamicAudioService.isAudioFeatureEnabled(AUDIO_FEATURE_DYNAMIC_ROUTING)) |
| .isFalse(); |
| } |
| |
| @Test |
| public void isAudioFeatureEnabled_forVolumeGroupMuting() { |
| mCarAudioService.init(); |
| |
| expectWithMessage("Group muting audio feature") |
| .that(mCarAudioService.isAudioFeatureEnabled(AUDIO_FEATURE_VOLUME_GROUP_MUTING)) |
| .isEqualTo(mUseCarVolumeGroupMuting); |
| } |
| |
| @Test |
| public void isAudioFeatureEnabled_forDisabledVolumeGroupMuting() { |
| when(mMockResources.getBoolean(audioUseCarVolumeGroupMuting)).thenReturn(false); |
| CarAudioService nonVolumeGroupMutingAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| nonVolumeGroupMutingAudioService.init(); |
| |
| expectWithMessage("Disabled group muting audio feature") |
| .that(nonVolumeGroupMutingAudioService |
| .isAudioFeatureEnabled(AUDIO_FEATURE_VOLUME_GROUP_MUTING)) |
| .isFalse(); |
| } |
| |
| @Test |
| public void isAudioFeatureEnabled_forVolumeGroupEvent() { |
| mCarAudioService.init(); |
| |
| expectWithMessage("Group events audio feature") |
| .that(mCarAudioService.isAudioFeatureEnabled(AUDIO_FEATURE_VOLUME_GROUP_EVENTS)) |
| .isEqualTo(mUseCarVolumeGroupEvents); |
| } |
| |
| @Test |
| public void isAudioFeatureEnabled_forDisabledVolumeGroupEvent() { |
| when(mMockResources.getBoolean(audioUseCarVolumeGroupEvent)).thenReturn(false); |
| CarAudioService nonVolumeGroupEventsAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| nonVolumeGroupEventsAudioService.init(); |
| |
| expectWithMessage("Disabled group event audio feature") |
| .that(nonVolumeGroupEventsAudioService |
| .isAudioFeatureEnabled(AUDIO_FEATURE_VOLUME_GROUP_EVENTS)) |
| .isFalse(); |
| } |
| |
| @Test |
| public void isAudioFeatureEnabled_forUnrecognizableAudioFeature_throws() { |
| mCarAudioService.init(); |
| |
| IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, |
| () -> mCarAudioService.isAudioFeatureEnabled(INVALID_AUDIO_FEATURE)); |
| |
| expectWithMessage("Unknown audio feature") |
| .that(thrown).hasMessageThat() |
| .contains("Unknown Audio Feature type: " + INVALID_AUDIO_FEATURE); |
| } |
| |
| @Test |
| public void isAudioFeatureEnabled_forDisabledOemService() { |
| mCarAudioService.init(); |
| |
| boolean isEnabled = |
| mCarAudioService.isAudioFeatureEnabled(AUDIO_FEATURE_OEM_AUDIO_SERVICE); |
| |
| expectWithMessage("Oem service enabled with disabled oem service") |
| .that(isEnabled).isFalse(); |
| } |
| |
| @Test |
| public void isAudioFeatureEnabled_withEnabledFocusService() { |
| CarOemAudioFocusProxyService service = mock(CarOemAudioFocusProxyService.class); |
| when(mMockCarOemProxyService.isOemServiceEnabled()).thenReturn(true); |
| when(mMockCarOemProxyService.getCarOemAudioFocusService()).thenReturn(service); |
| mCarAudioService.init(); |
| |
| boolean isEnabled = |
| mCarAudioService.isAudioFeatureEnabled(AUDIO_FEATURE_OEM_AUDIO_SERVICE); |
| |
| expectWithMessage("Oem service enabled with enabled focus service") |
| .that(isEnabled).isTrue(); |
| } |
| |
| @Test |
| public void isAudioFeatureEnabled_withEnabledVolumeService() { |
| CarOemAudioVolumeProxyService service = mock(CarOemAudioVolumeProxyService.class); |
| when(mMockCarOemProxyService.isOemServiceEnabled()).thenReturn(true); |
| when(mMockCarOemProxyService.getCarOemAudioVolumeService()).thenReturn(service); |
| mCarAudioService.init(); |
| |
| boolean isEnabled = |
| mCarAudioService.isAudioFeatureEnabled(AUDIO_FEATURE_OEM_AUDIO_SERVICE); |
| |
| expectWithMessage("Oem service enabled with enabled volume service") |
| .that(isEnabled).isTrue(); |
| } |
| |
| @Test |
| public void isAudioFeatureEnabled_withEnabledDuckingService() { |
| CarOemAudioDuckingProxyService service = mock(CarOemAudioDuckingProxyService.class); |
| when(mMockCarOemProxyService.isOemServiceEnabled()).thenReturn(true); |
| when(mMockCarOemProxyService.getCarOemAudioDuckingService()).thenReturn(service); |
| mCarAudioService.init(); |
| |
| boolean isEnabled = |
| mCarAudioService.isAudioFeatureEnabled(AUDIO_FEATURE_OEM_AUDIO_SERVICE); |
| |
| expectWithMessage("Oem service enabled with enabled ducking service") |
| .that(isEnabled).isTrue(); |
| } |
| |
| @Test |
| public void isAudioFeatureEnabled_withEnabledAudioMirror() { |
| mCarAudioService.init(); |
| |
| boolean isEnabled = mCarAudioService.isAudioFeatureEnabled(AUDIO_FEATURE_AUDIO_MIRRORING); |
| |
| expectWithMessage("Audio mirror enabled status") |
| .that(isEnabled).isTrue(); |
| } |
| |
| @Test |
| public void isAudioFeatureEnabled_withDisabledAudioMirror() { |
| CarAudioService carAudioService = getCarAudioServiceWithoutMirroring(); |
| carAudioService.init(); |
| |
| boolean isEnabled = carAudioService.isAudioFeatureEnabled(AUDIO_FEATURE_AUDIO_MIRRORING); |
| |
| expectWithMessage("Audio mirror enabled status") |
| .that(isEnabled).isFalse(); |
| } |
| |
| @Test |
| public void onOccupantZoneConfigChanged_noUserAssignedToPrimaryZone() throws Exception { |
| mCarAudioService.init(); |
| when(mMockOccupantZoneService.getDriverUserId()).thenReturn(UserManagerHelper.USER_NULL); |
| when(mMockOccupantZoneService.getUserForOccupant(anyInt())) |
| .thenReturn(UserManagerHelper.USER_NULL); |
| ICarOccupantZoneCallback callback = getOccupantZoneCallback(); |
| int prevUserId = mCarAudioService.getUserIdForZone(PRIMARY_AUDIO_ZONE); |
| |
| callback.onOccupantZoneConfigChanged(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER); |
| |
| expectWithMessage("User ID before config changed") |
| .that(mCarAudioService.getUserIdForZone(PRIMARY_AUDIO_ZONE)) |
| .isEqualTo(prevUserId); |
| } |
| |
| @Test |
| public void onOccupantZoneConfigChanged_userAssignedToPrimaryZone() throws Exception { |
| mCarAudioService.init(); |
| when(mMockOccupantZoneService.getDriverUserId()).thenReturn(TEST_DRIVER_USER_ID); |
| when(mMockOccupantZoneService.getUserForOccupant(anyInt())) |
| .thenReturn(TEST_REAR_LEFT_USER_ID); |
| ICarOccupantZoneCallback callback = getOccupantZoneCallback(); |
| |
| callback.onOccupantZoneConfigChanged(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER); |
| |
| expectWithMessage("User ID after config changed") |
| .that(mCarAudioService.getUserIdForZone(PRIMARY_AUDIO_ZONE)) |
| .isEqualTo(TEST_REAR_LEFT_USER_ID); |
| } |
| |
| @Test |
| public void onOccupantZoneConfigChanged_afterResettingUser_returnNoUser() throws Exception { |
| mCarAudioService.init(); |
| when(mMockOccupantZoneService.getDriverUserId()).thenReturn(TEST_DRIVER_USER_ID); |
| when(mMockOccupantZoneService.getUserForOccupant(anyInt())) |
| .thenReturn(TEST_REAR_LEFT_USER_ID); |
| ICarOccupantZoneCallback callback = getOccupantZoneCallback(); |
| callback.onOccupantZoneConfigChanged(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER); |
| when(mMockOccupantZoneService.getUserForOccupant(anyInt())) |
| .thenReturn(UserManagerHelper.USER_NULL); |
| |
| callback.onOccupantZoneConfigChanged(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER); |
| |
| expectWithMessage("User ID config changed to null") |
| .that(mCarAudioService.getUserIdForZone(PRIMARY_AUDIO_ZONE)) |
| .isEqualTo(UserManagerHelper.USER_NULL); |
| } |
| |
| @Test |
| public void onOccupantZoneConfigChanged_noOccupantZoneMapping() throws Exception { |
| CarAudioService noZoneMappingAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| noZoneMappingAudioService.init(); |
| ICarOccupantZoneCallback callback = getOccupantZoneCallback(); |
| |
| callback.onOccupantZoneConfigChanged(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER); |
| |
| verify(mMockOccupantZoneService, never()).getUserForOccupant(anyInt()); |
| } |
| |
| @Test |
| public void onOccupantZoneConfigChanged_noOccupantZoneMapping_alreadyAssigned() |
| throws Exception { |
| CarAudioService noZoneMappingAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationWithoutZoneMappingFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| when(mMockOccupantZoneService.getDriverUserId()).thenReturn(TEST_DRIVER_USER_ID); |
| noZoneMappingAudioService.init(); |
| ICarOccupantZoneCallback callback = getOccupantZoneCallback(); |
| callback.onOccupantZoneConfigChanged(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER); |
| callback.onOccupantZoneConfigChanged(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER); |
| |
| verify(mMockOccupantZoneService, never()).getUserForOccupant(anyInt()); |
| expectWithMessage("Occupant Zone for primary zone") |
| .that(noZoneMappingAudioService.getUserIdForZone(PRIMARY_AUDIO_ZONE)) |
| .isEqualTo(TEST_DRIVER_USER_ID); |
| } |
| |
| @Test |
| public void onOccupantZoneConfigChanged_multipleZones() throws Exception { |
| mCarAudioService.init(); |
| when(mMockOccupantZoneService.getDriverUserId()).thenReturn(TEST_DRIVER_USER_ID); |
| when(mMockOccupantZoneService.getUserForOccupant(anyInt())) |
| .thenReturn(TEST_REAR_LEFT_USER_ID, TEST_REAR_RIGHT_USER_ID); |
| ICarOccupantZoneCallback callback = getOccupantZoneCallback(); |
| |
| callback.onOccupantZoneConfigChanged(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER); |
| |
| expectWithMessage("User ID for primary and secondary zone after config changed") |
| .that(mCarAudioService.getUserIdForZone(PRIMARY_AUDIO_ZONE)) |
| .isNotEqualTo(mCarAudioService.getUserIdForZone(TEST_REAR_LEFT_ZONE_ID)); |
| expectWithMessage("Secondary user ID config changed") |
| .that(mCarAudioService.getUserIdForZone(TEST_REAR_LEFT_ZONE_ID)) |
| .isEqualTo(TEST_REAR_RIGHT_USER_ID); |
| } |
| |
| @Test |
| public void serviceDied_registersAudioGainCallback() { |
| mCarAudioService.init(); |
| ArgumentCaptor<AudioControlDeathRecipient> captor = |
| ArgumentCaptor.forClass(AudioControlDeathRecipient.class); |
| verify(mAudioControlWrapperAidl).linkToDeath(captor.capture()); |
| AudioControlDeathRecipient runnable = captor.getValue(); |
| reset(mAudioControlWrapperAidl); |
| |
| runnable.serviceDied(); |
| |
| verify(mAudioControlWrapperAidl).registerAudioGainCallback(any()); |
| } |
| |
| @Test |
| public void serviceDied_registersFocusListener() { |
| mCarAudioService.init(); |
| ArgumentCaptor<AudioControlDeathRecipient> captor = |
| ArgumentCaptor.forClass(AudioControlDeathRecipient.class); |
| verify(mAudioControlWrapperAidl).linkToDeath(captor.capture()); |
| AudioControlDeathRecipient runnable = captor.getValue(); |
| reset(mAudioControlWrapperAidl); |
| |
| runnable.serviceDied(); |
| |
| verify(mAudioControlWrapperAidl).registerFocusListener(any()); |
| } |
| |
| @Test |
| public void serviceDied_setsModuleChangeCallback() { |
| mCarAudioService.init(); |
| ArgumentCaptor<AudioControlDeathRecipient> captor = |
| ArgumentCaptor.forClass(AudioControlDeathRecipient.class); |
| verify(mAudioControlWrapperAidl).linkToDeath(captor.capture()); |
| AudioControlDeathRecipient runnable = captor.getValue(); |
| reset(mAudioControlWrapperAidl); |
| |
| runnable.serviceDied(); |
| |
| verify(mAudioControlWrapperAidl).setModuleChangeCallback(any()); |
| } |
| |
| private ICarOccupantZoneCallback getOccupantZoneCallback() { |
| ArgumentCaptor<ICarOccupantZoneCallback> captor = |
| ArgumentCaptor.forClass(ICarOccupantZoneCallback.class); |
| verify(mMockOccupantZoneService).registerCallback(captor.capture()); |
| return captor.getValue(); |
| } |
| |
| @Test |
| public void getVolumeGroupIdForAudioContext_forPrimaryGroup() { |
| mCarAudioService.init(); |
| |
| expectWithMessage("Volume group ID for primary audio zone") |
| .that(mCarAudioService.getVolumeGroupIdForAudioContext(PRIMARY_AUDIO_ZONE, |
| CarAudioContext.MUSIC)) |
| .isEqualTo(TEST_PRIMARY_GROUP_INDEX); |
| } |
| |
| @Test |
| public void getVolumeGroupIdForAudioAttribute() { |
| mCarAudioService.init(); |
| |
| expectWithMessage("Volume group ID for primary audio zone") |
| .that(mCarAudioService.getVolumeGroupIdForAudioAttribute(PRIMARY_AUDIO_ZONE, |
| CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA))) |
| .isEqualTo(TEST_PRIMARY_GROUP_INDEX); |
| } |
| |
| @Test |
| public void getVolumeGroupIdForAudioAttribute_withNullAttribute_fails() { |
| mCarAudioService.init(); |
| |
| NullPointerException thrown = assertThrows(NullPointerException.class, () -> |
| mCarAudioService.getVolumeGroupIdForAudioAttribute(PRIMARY_AUDIO_ZONE, |
| /* attribute= */ null)); |
| |
| expectWithMessage("Null audio attribute exception").that(thrown).hasMessageThat() |
| .contains("Audio attributes"); |
| } |
| |
| @Test |
| public void getVolumeGroupIdForAudioAttribute_withInvalidZoneId_fails() { |
| mCarAudioService.init(); |
| |
| IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> |
| mCarAudioService.getVolumeGroupIdForAudioAttribute(INVALID_AUDIO_ZONE, |
| CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA))); |
| |
| expectWithMessage("Invalid audio zone exception").that(thrown).hasMessageThat() |
| .contains("Invalid audio zone Id"); |
| } |
| |
| @Test |
| public void getInputDevicesForZoneId_primaryZone() { |
| mCarAudioService.init(); |
| |
| expectWithMessage("Get input device for primary zone id") |
| .that(mCarAudioService.getInputDevicesForZoneId(PRIMARY_AUDIO_ZONE)) |
| .containsExactly(new AudioDeviceAttributes(mMicrophoneInputDevice)); |
| } |
| |
| @Test |
| public void getExternalSources_forSingleDevice() { |
| mCarAudioService.init(); |
| AudioDeviceInfo[] inputDevices = generateInputDeviceInfos(); |
| |
| expectWithMessage("External input device addresses") |
| .that(mCarAudioService.getExternalSources()) |
| .asList().containsExactly(inputDevices[1].getAddress()); |
| } |
| |
| @Test |
| public void setAudioEnabled_forEnabledVolumeGroupMuting() { |
| mCarAudioService.init(); |
| |
| mCarAudioService.setAudioEnabled(/* enabled= */ true); |
| |
| verify(mAudioControlWrapperAidl).onDevicesToMuteChange(any()); |
| } |
| |
| @Test |
| public void setAudioEnabled_forDisabledVolumeGroupMuting() { |
| when(mMockResources.getBoolean(audioUseCarVolumeGroupMuting)).thenReturn(false); |
| CarAudioService nonVolumeGroupMutingAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| nonVolumeGroupMutingAudioService.init(); |
| |
| nonVolumeGroupMutingAudioService.setAudioEnabled(/* enabled= */ true); |
| |
| verify(mAudioControlWrapperAidl, never()).onDevicesToMuteChange(any()); |
| } |
| |
| @Test |
| public void registerVolumeCallback_verifyCallbackHandler() { |
| int uid = Binder.getCallingUid(); |
| mCarAudioService.init(); |
| |
| mCarAudioService.registerVolumeCallback(mVolumeCallbackBinder); |
| |
| verify(mCarVolumeCallbackHandler).registerCallback(mVolumeCallbackBinder, uid, true); |
| } |
| |
| @Test |
| public void unregisterVolumeCallback_verifyCallbackHandler() { |
| int uid = Binder.getCallingUid(); |
| mCarAudioService.init(); |
| |
| mCarAudioService.unregisterVolumeCallback(mVolumeCallbackBinder); |
| |
| verify(mCarVolumeCallbackHandler).unregisterCallback(mVolumeCallbackBinder, uid); |
| } |
| |
| @Test |
| public void getMutedVolumeGroups_forInvalidZone() { |
| mCarAudioService.init(); |
| |
| expectWithMessage("Muted volume groups for invalid zone") |
| .that(mCarAudioService.getMutedVolumeGroups(INVALID_AUDIO_ZONE)) |
| .isEmpty(); |
| } |
| |
| @Test |
| public void getMutedVolumeGroups_whenVolumeGroupMuteNotSupported() { |
| when(mMockResources.getBoolean(audioUseCarVolumeGroupMuting)).thenReturn(false); |
| CarAudioService nonVolumeGroupMutingAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| nonVolumeGroupMutingAudioService.init(); |
| |
| expectWithMessage("Muted volume groups with disable mute feature") |
| .that(nonVolumeGroupMutingAudioService.getMutedVolumeGroups(PRIMARY_AUDIO_ZONE)) |
| .isEmpty(); |
| } |
| |
| @Test |
| public void getMutedVolumeGroups_withMutedGroups() { |
| mCarAudioService.init(); |
| mCarAudioService.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP, |
| /* muted= */ true, TEST_FLAGS); |
| mCarAudioService.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_SECONDARY_GROUP, |
| /* muted= */ true, TEST_FLAGS); |
| |
| expectWithMessage("Muted volume groups") |
| .that(mCarAudioService.getMutedVolumeGroups(PRIMARY_AUDIO_ZONE)) |
| .containsExactly(TEST_PRIMARY_VOLUME_INFO, TEST_SECONDARY_VOLUME_INFO); |
| } |
| |
| @Test |
| public void getMutedVolumeGroups_afterUnmuting() { |
| mCarAudioService.init(); |
| mCarAudioService.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP, |
| /* muted= */ true, TEST_FLAGS); |
| mCarAudioService.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_SECONDARY_GROUP, |
| /* muted= */ true, TEST_FLAGS); |
| mCarAudioService.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP, |
| /* muted= */ false, TEST_FLAGS); |
| |
| expectWithMessage("Muted volume groups after unmuting one group") |
| .that(mCarAudioService.getMutedVolumeGroups(PRIMARY_AUDIO_ZONE)) |
| .containsExactly(TEST_SECONDARY_VOLUME_INFO); |
| } |
| |
| @Test |
| public void getMutedVolumeGroups_withMutedGroupsForDifferentZone() { |
| mCarAudioService.init(); |
| mCarAudioService.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP, |
| /* muted= */ true, TEST_FLAGS); |
| mCarAudioService.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_SECONDARY_GROUP, |
| /* muted= */ true, TEST_FLAGS); |
| |
| expectWithMessage("Muted volume groups for secondary zone") |
| .that(mCarAudioService.getMutedVolumeGroups(TEST_REAR_LEFT_ZONE_ID)).isEmpty(); |
| } |
| |
| @Test |
| public void onReceive_forLegacy_noCallToOnVolumeGroupChanged() { |
| when(mMockResources.getBoolean(audioUseDynamicRouting)) |
| .thenReturn(false); |
| CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| nonDynamicAudioService.init(); |
| mVolumeReceiverCaptor = ArgumentCaptor.forClass(BroadcastReceiver.class); |
| verify(mMockContext).registerReceiver(mVolumeReceiverCaptor.capture(), any(), anyInt()); |
| BroadcastReceiver receiver = mVolumeReceiverCaptor.getValue(); |
| Intent intent = new Intent(VOLUME_CHANGED_ACTION); |
| |
| receiver.onReceive(mMockContext, intent); |
| |
| verify(mCarVolumeCallbackHandler, never()) |
| .onVolumeGroupChange(anyInt(), anyInt(), anyInt()); |
| } |
| |
| @Test |
| public void onReceive_forLegacy_forStreamMusic() { |
| when(mMockResources.getBoolean(audioUseDynamicRouting)) |
| .thenReturn(false); |
| CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| nonDynamicAudioService.init(); |
| verify(mMockContext).registerReceiver(mVolumeReceiverCaptor.capture(), any(), anyInt()); |
| BroadcastReceiver receiver = mVolumeReceiverCaptor.getValue(); |
| Intent intent = new Intent(VOLUME_CHANGED_ACTION) |
| .putExtra(EXTRA_VOLUME_STREAM_TYPE, STREAM_MUSIC); |
| |
| receiver.onReceive(mMockContext, intent); |
| |
| verify(mCarVolumeCallbackHandler).onVolumeGroupChange( |
| eq(PRIMARY_AUDIO_ZONE), anyInt(), eq(FLAG_FROM_KEY | FLAG_SHOW_UI)); |
| } |
| |
| @Test |
| public void onReceive_forLegacy_onMuteChanged() { |
| when(mMockResources.getBoolean(audioUseDynamicRouting)) |
| .thenReturn(false); |
| CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| nonDynamicAudioService.init(); |
| ArgumentCaptor<BroadcastReceiver> captor = |
| ArgumentCaptor.forClass(BroadcastReceiver.class); |
| verify(mMockContext).registerReceiver(captor.capture(), any(), anyInt()); |
| BroadcastReceiver receiver = captor.getValue(); |
| Intent intent = new Intent(); |
| intent.setAction(MASTER_MUTE_CHANGED_ACTION); |
| |
| receiver.onReceive(mMockContext, intent); |
| |
| verify(mCarVolumeCallbackHandler) |
| .onMasterMuteChanged(eq(PRIMARY_AUDIO_ZONE), eq(FLAG_FROM_KEY | FLAG_SHOW_UI)); |
| } |
| |
| @Test |
| public void getVolumeGroupInfosForZone() { |
| mCarAudioService.init(); |
| int groupCount = mCarAudioService.getVolumeGroupCount(PRIMARY_AUDIO_ZONE); |
| |
| List<CarVolumeGroupInfo> infos = |
| mCarAudioService.getVolumeGroupInfosForZone(PRIMARY_AUDIO_ZONE); |
| |
| for (int index = 0; index < groupCount; index++) { |
| CarVolumeGroupInfo info = mCarAudioService |
| .getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, index); |
| expectWithMessage("Car volume group infos for primary zone and info %s", info) |
| .that(infos).contains(info); |
| } |
| } |
| |
| @Test |
| public void getVolumeGroupInfosForZone_forDynamicRoutingDisabled() { |
| when(mMockResources.getBoolean(audioUseDynamicRouting)) |
| .thenReturn(/* useDynamicRouting= */ false); |
| CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| nonDynamicAudioService.init(); |
| |
| List<CarVolumeGroupInfo> infos = |
| nonDynamicAudioService.getVolumeGroupInfosForZone(PRIMARY_AUDIO_ZONE); |
| |
| expectWithMessage("Car volume group infos with dynamic routing disabled") |
| .that(infos).isEmpty(); |
| } |
| |
| @Test |
| public void getVolumeGroupInfosForZone_size() { |
| mCarAudioService.init(); |
| int groupCount = mCarAudioService.getVolumeGroupCount(PRIMARY_AUDIO_ZONE); |
| |
| List<CarVolumeGroupInfo> infos = |
| mCarAudioService.getVolumeGroupInfosForZone(PRIMARY_AUDIO_ZONE); |
| |
| expectWithMessage("Car volume group infos size for primary zone") |
| .that(infos).hasSize(groupCount); |
| } |
| |
| @Test |
| public void getVolumeGroupInfosForZone_forInvalidZone() { |
| mCarAudioService.init(); |
| |
| IllegalArgumentException thrown = |
| assertThrows(IllegalArgumentException.class, () -> |
| mCarAudioService.getVolumeGroupInfosForZone(INVALID_AUDIO_ZONE)); |
| |
| expectWithMessage("Exception for volume group infos size for invalid zone") |
| .that(thrown).hasMessageThat().contains("audio zone Id"); |
| } |
| |
| @Test |
| public void getVolumeGroupInfo() { |
| CarVolumeGroupInfo testVolumeGroupInfo = |
| new CarVolumeGroupInfo.Builder(TEST_PRIMARY_VOLUME_INFO).setMuted(false).build(); |
| mCarAudioService.init(); |
| |
| expectWithMessage("Car volume group info for primary zone") |
| .that(mCarAudioService.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP)) |
| .isEqualTo(testVolumeGroupInfo); |
| } |
| |
| @Test |
| public void getVolumeGroupInfo_forInvalidZone() { |
| mCarAudioService.init(); |
| |
| IllegalArgumentException thrown = |
| assertThrows(IllegalArgumentException.class, () -> |
| mCarAudioService.getVolumeGroupInfo(INVALID_AUDIO_ZONE, |
| TEST_PRIMARY_GROUP)); |
| |
| expectWithMessage("Exception for volume group info size for invalid zone") |
| .that(thrown).hasMessageThat().contains("audio zone Id"); |
| } |
| |
| @Test |
| public void getVolumeGroupInfo_forInvalidGroup() { |
| mCarAudioService.init(); |
| |
| IllegalArgumentException thrown = |
| assertThrows(IllegalArgumentException.class, () -> |
| mCarAudioService.getVolumeGroupInfo(INVALID_AUDIO_ZONE, |
| TEST_PRIMARY_GROUP)); |
| |
| expectWithMessage("Exception for volume groups info size for invalid group id") |
| .that(thrown).hasMessageThat().contains("audio zone Id"); |
| } |
| |
| @Test |
| public void getVolumeGroupInfo_forGroupOverRange() { |
| mCarAudioService.init(); |
| int groupCount = mCarAudioService.getVolumeGroupCount(PRIMARY_AUDIO_ZONE); |
| |
| IllegalArgumentException thrown = |
| assertThrows(IllegalArgumentException.class, () -> |
| mCarAudioService.getVolumeGroupInfo(INVALID_AUDIO_ZONE, |
| groupCount)); |
| |
| expectWithMessage("Exception for volume groups info size for out of range group") |
| .that(thrown).hasMessageThat().contains("audio zone Id"); |
| } |
| |
| @Test |
| public void registerPrimaryZoneMediaAudioRequestCallbackListener_withNullCallback_fails() { |
| mCarAudioService.init(); |
| |
| NullPointerException thrown = assertThrows(NullPointerException.class, () |
| -> mCarAudioService.registerPrimaryZoneMediaAudioRequestCallback( |
| /* callback= */ null)); |
| |
| expectWithMessage("Register audio media request callback exception") |
| .that(thrown).hasMessageThat() |
| .contains("Media request callback"); |
| } |
| |
| @Test |
| public void unregisterPrimaryZoneMediaAudioRequestCallback_withNullCallback_fails() { |
| mCarAudioService.init(); |
| |
| NullPointerException thrown = assertThrows(NullPointerException.class, () |
| -> mCarAudioService.unregisterPrimaryZoneMediaAudioRequestCallback( |
| /* callback= */ null)); |
| |
| expectWithMessage("Unregister audio media request callback exception") |
| .that(thrown).hasMessageThat() |
| .contains("Media request callback"); |
| } |
| |
| @Test |
| public void requestMediaAudioOnPrimaryZone_withPassengerOccupant_succeeds() |
| throws Exception { |
| mCarAudioService.init(); |
| TestPrimaryZoneMediaAudioRequestCallback |
| requestToken = new TestPrimaryZoneMediaAudioRequestCallback(); |
| TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback(); |
| assignOccupantToAudioZones(); |
| mCarAudioService.registerPrimaryZoneMediaAudioRequestCallback(requestToken); |
| |
| expectWithMessage("Audio media request id") |
| .that(mCarAudioService.requestMediaAudioOnPrimaryZone(requestCallback, |
| TEST_REAR_RIGHT_PASSENGER_OCCUPANT)) |
| .isNotEqualTo(INVALID_REQUEST_ID); |
| } |
| |
| @Test |
| public void requestMediaAudioOnPrimaryZone_withDriverOccupant_fails() |
| throws Exception { |
| mCarAudioService.init(); |
| TestPrimaryZoneMediaAudioRequestCallback |
| requestToken = new TestPrimaryZoneMediaAudioRequestCallback(); |
| TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback(); |
| assignOccupantToAudioZones(); |
| mCarAudioService.registerPrimaryZoneMediaAudioRequestCallback(requestToken); |
| |
| IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () |
| -> mCarAudioService.requestMediaAudioOnPrimaryZone(requestCallback, |
| TEST_DRIVER_OCCUPANT)); |
| |
| expectWithMessage("Request media audio exception") |
| .that(thrown).hasMessageThat().contains("already owns the primary audio zone"); |
| } |
| |
| @Test |
| public void requestMediaAudioOnPrimaryZone_withNonAssignedOccupant_fails() |
| throws Exception { |
| when(mMockOccupantZoneService.getAudioZoneIdForOccupant(TEST_UNASSIGNED_OCCUPANT_ZONE_ID)) |
| .thenReturn(/* audioZoneId= */ 4); |
| mCarAudioService.init(); |
| TestPrimaryZoneMediaAudioRequestCallback |
| requestToken = new TestPrimaryZoneMediaAudioRequestCallback(); |
| TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback(); |
| CarOccupantZoneManager.OccupantZoneInfo info = |
| getOccupantInfo(TEST_UNASSIGNED_OCCUPANT_ZONE_ID, |
| CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER, |
| VehicleAreaSeat.SEAT_ROW_1_LEFT); |
| assignOccupantToAudioZones(); |
| mCarAudioService.registerPrimaryZoneMediaAudioRequestCallback(requestToken); |
| |
| expectWithMessage("Invalid audio media request id") |
| .that(mCarAudioService.requestMediaAudioOnPrimaryZone(requestCallback, info)) |
| .isEqualTo(INVALID_REQUEST_ID); |
| } |
| |
| @Test |
| public void requestMediaAudioOnPrimaryZone_withPassengerOccupant_callsApprover() |
| throws Exception { |
| mCarAudioService.init(); |
| TestPrimaryZoneMediaAudioRequestCallback |
| requestToken = new TestPrimaryZoneMediaAudioRequestCallback(); |
| TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback(); |
| assignOccupantToAudioZones(); |
| mCarAudioService.registerPrimaryZoneMediaAudioRequestCallback(requestToken); |
| |
| long requestId = mCarAudioService.requestMediaAudioOnPrimaryZone(requestCallback, |
| TEST_REAR_RIGHT_PASSENGER_OCCUPANT); |
| |
| requestToken.waitForCallback(); |
| expectWithMessage("Called audio media request id") |
| .that(requestToken.mRequestId).isEqualTo(requestId); |
| expectWithMessage("Called audio media request info") |
| .that(requestToken.mInfo).isEqualTo(TEST_REAR_RIGHT_PASSENGER_OCCUPANT); |
| } |
| |
| @Test |
| public void allowMediaAudioOnPrimaryZone_withAllowedRequest() throws Exception { |
| mCarAudioService.init(); |
| TestPrimaryZoneMediaAudioRequestCallback |
| requestToken = new TestPrimaryZoneMediaAudioRequestCallback(); |
| TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback(); |
| assignOccupantToAudioZones(); |
| mCarAudioService.registerPrimaryZoneMediaAudioRequestCallback(requestToken); |
| long requestId = mCarAudioService.requestMediaAudioOnPrimaryZone(requestCallback, |
| TEST_REAR_RIGHT_PASSENGER_OCCUPANT); |
| requestToken.waitForCallback(); |
| |
| boolean results = mCarAudioService.allowMediaAudioOnPrimaryZone(requestToken, requestId, |
| /* allowed= */ true); |
| |
| expectWithMessage("Allowed audio playback").that(results).isTrue(); |
| } |
| |
| @Test |
| public void allowMediaAudioOnPrimaryZone_withUnallowedRequest() throws Exception { |
| mCarAudioService.init(); |
| TestPrimaryZoneMediaAudioRequestCallback |
| requestToken = new TestPrimaryZoneMediaAudioRequestCallback(); |
| TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback(); |
| assignOccupantToAudioZones(); |
| mCarAudioService.registerPrimaryZoneMediaAudioRequestCallback(requestToken); |
| long requestId = mCarAudioService.requestMediaAudioOnPrimaryZone(requestCallback, |
| TEST_REAR_RIGHT_PASSENGER_OCCUPANT); |
| requestToken.waitForCallback(); |
| |
| boolean results = mCarAudioService.allowMediaAudioOnPrimaryZone(requestToken, requestId, |
| /* allowed= */ false); |
| |
| expectWithMessage("Unallowed audio playback").that(results).isTrue(); |
| } |
| |
| @Test |
| public void allowMediaAudioOnPrimaryZone_withAllowedRequest_callsRequester() throws Exception { |
| mCarAudioService.init(); |
| TestPrimaryZoneMediaAudioRequestCallback |
| requestToken = new TestPrimaryZoneMediaAudioRequestCallback(); |
| TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback(); |
| assignOccupantToAudioZones(); |
| mCarAudioService.registerPrimaryZoneMediaAudioRequestCallback(requestToken); |
| long requestId = mCarAudioService.requestMediaAudioOnPrimaryZone(requestCallback, |
| TEST_REAR_RIGHT_PASSENGER_OCCUPANT); |
| requestToken.waitForCallback(); |
| |
| mCarAudioService.allowMediaAudioOnPrimaryZone(requestToken, requestId, |
| /* allowed= */ true); |
| |
| requestCallback.waitForCallback(); |
| expectWithMessage("Media request called audio media request id") |
| .that(requestCallback.mRequestId).isEqualTo(requestId); |
| expectWithMessage("Media request called audio media request info") |
| .that(requestCallback.mInfo).isEqualTo(TEST_REAR_RIGHT_PASSENGER_OCCUPANT); |
| expectWithMessage("Media request called audio media request status") |
| .that(requestCallback.mStatus) |
| .isEqualTo(CarAudioManager.AUDIO_REQUEST_STATUS_APPROVED); |
| } |
| |
| @Test |
| public void allowMediaAudioOnPrimaryZone_withAllowedRequest_callsApprover() throws Exception { |
| mCarAudioService.init(); |
| TestPrimaryZoneMediaAudioRequestCallback |
| requestApprover = new TestPrimaryZoneMediaAudioRequestCallback(); |
| TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback(); |
| assignOccupantToAudioZones(); |
| mCarAudioService.registerPrimaryZoneMediaAudioRequestCallback(requestApprover); |
| long requestId = mCarAudioService.requestMediaAudioOnPrimaryZone(requestCallback, |
| TEST_REAR_RIGHT_PASSENGER_OCCUPANT); |
| requestApprover.waitForCallback(); |
| requestApprover.reset(); |
| |
| mCarAudioService.allowMediaAudioOnPrimaryZone(requestApprover, requestId, |
| /* allowed= */ true); |
| |
| requestApprover.waitForCallback(); |
| expectWithMessage("Media approver called audio media request id") |
| .that(requestApprover.mRequestId).isEqualTo(requestId); |
| expectWithMessage("Media approver called audio media request info") |
| .that(requestApprover.mInfo).isEqualTo(TEST_REAR_RIGHT_PASSENGER_OCCUPANT); |
| expectWithMessage("Media approver called audio media request status") |
| .that(requestApprover.mStatus) |
| .isEqualTo(CarAudioManager.AUDIO_REQUEST_STATUS_APPROVED); |
| } |
| |
| @Test |
| public void allowMediaAudioOnPrimaryZone_withUnallowedRequest_callsRequester() |
| throws Exception { |
| mCarAudioService.init(); |
| TestPrimaryZoneMediaAudioRequestCallback |
| requestToken = new TestPrimaryZoneMediaAudioRequestCallback(); |
| TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback(); |
| assignOccupantToAudioZones(); |
| mCarAudioService.registerPrimaryZoneMediaAudioRequestCallback(requestToken); |
| long requestId = mCarAudioService.requestMediaAudioOnPrimaryZone(requestCallback, |
| TEST_REAR_RIGHT_PASSENGER_OCCUPANT); |
| requestToken.waitForCallback(); |
| |
| mCarAudioService.allowMediaAudioOnPrimaryZone(requestToken, requestId, |
| /* allowed= */ false); |
| |
| requestCallback.waitForCallback(); |
| expectWithMessage("Unallowed media request called audio media request id") |
| .that(requestCallback.mRequestId).isEqualTo(requestId); |
| expectWithMessage("Unallowed media request called audio media request info") |
| .that(requestCallback.mInfo).isEqualTo(TEST_REAR_RIGHT_PASSENGER_OCCUPANT); |
| expectWithMessage("Unallowed media request called audio media request status") |
| .that(requestCallback.mStatus) |
| .isEqualTo(CarAudioManager.AUDIO_REQUEST_STATUS_REJECTED); |
| } |
| |
| @Test |
| public void allowMediaAudioOnPrimaryZone_withUnallowedRequest_callsApprover() throws Exception { |
| mCarAudioService.init(); |
| TestPrimaryZoneMediaAudioRequestCallback |
| requestApprover = new TestPrimaryZoneMediaAudioRequestCallback(); |
| TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback(); |
| assignOccupantToAudioZones(); |
| mCarAudioService.registerPrimaryZoneMediaAudioRequestCallback(requestApprover); |
| long requestId = mCarAudioService.requestMediaAudioOnPrimaryZone(requestCallback, |
| TEST_REAR_RIGHT_PASSENGER_OCCUPANT); |
| requestApprover.waitForCallback(); |
| requestApprover.reset(); |
| |
| mCarAudioService.allowMediaAudioOnPrimaryZone(requestApprover, requestId, |
| /* allowed= */ false); |
| |
| requestApprover.waitForCallback(); |
| expectWithMessage("Unallowed media approver called audio media request id") |
| .that(requestApprover.mRequestId).isEqualTo(requestId); |
| expectWithMessage("Unallowed approver token called audio media request info") |
| .that(requestApprover.mInfo).isEqualTo(TEST_REAR_RIGHT_PASSENGER_OCCUPANT); |
| expectWithMessage("Unallowed approver token called audio media request status") |
| .that(requestApprover.mStatus) |
| .isEqualTo(CarAudioManager.AUDIO_REQUEST_STATUS_REJECTED); |
| } |
| |
| @Test |
| public void isMediaAudioAllowedInPrimaryZone_witNullOccupant_fails() throws Exception { |
| mCarAudioService.init(); |
| NullPointerException thrown = assertThrows(NullPointerException.class, () |
| -> mCarAudioService.isMediaAudioAllowedInPrimaryZone(/* occupantZoneInfo= */ null)); |
| |
| expectWithMessage("Media status exception").that(thrown) |
| .hasMessageThat().contains("Occupant zone info"); |
| } |
| |
| @Test |
| public void isMediaAudioAllowedInPrimaryZone_byDefault() throws Exception { |
| mCarAudioService.init(); |
| |
| expectWithMessage("Media default status") |
| .that(mCarAudioService.isMediaAudioAllowedInPrimaryZone( |
| TEST_REAR_RIGHT_PASSENGER_OCCUPANT)) |
| .isFalse(); |
| } |
| |
| @Test |
| public void isMediaAudioAllowedInPrimaryZone_afterAllowed() throws Exception { |
| mCarAudioService.init(); |
| TestPrimaryZoneMediaAudioRequestCallback |
| requestToken = new TestPrimaryZoneMediaAudioRequestCallback(); |
| TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback(); |
| assignOccupantToAudioZones(); |
| mCarAudioService.registerPrimaryZoneMediaAudioRequestCallback(requestToken); |
| long requestId = mCarAudioService.requestMediaAudioOnPrimaryZone(requestCallback, |
| TEST_REAR_RIGHT_PASSENGER_OCCUPANT); |
| requestToken.waitForCallback(); |
| requestToken.reset(); |
| mCarAudioService.allowMediaAudioOnPrimaryZone(requestToken, requestId, |
| /* allowed= */ true); |
| requestToken.waitForCallback(); |
| |
| expectWithMessage("Media allowed status") |
| .that(mCarAudioService.isMediaAudioAllowedInPrimaryZone( |
| TEST_REAR_RIGHT_PASSENGER_OCCUPANT)) |
| .isTrue(); |
| } |
| |
| @Test |
| public void isMediaAudioAllowedInPrimaryZone_afterDisallowed() throws Exception { |
| mCarAudioService.init(); |
| TestPrimaryZoneMediaAudioRequestCallback |
| requestToken = new TestPrimaryZoneMediaAudioRequestCallback(); |
| TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback(); |
| assignOccupantToAudioZones(); |
| mCarAudioService.registerPrimaryZoneMediaAudioRequestCallback(requestToken); |
| long requestId = mCarAudioService.requestMediaAudioOnPrimaryZone(requestCallback, |
| TEST_REAR_RIGHT_PASSENGER_OCCUPANT); |
| requestToken.waitForCallback(); |
| requestToken.reset(); |
| mCarAudioService.allowMediaAudioOnPrimaryZone(requestToken, requestId, |
| /* allowed= */ false); |
| requestToken.waitForCallback(); |
| |
| expectWithMessage("Media after disallowed status") |
| .that(mCarAudioService.isMediaAudioAllowedInPrimaryZone( |
| TEST_REAR_RIGHT_PASSENGER_OCCUPANT)) |
| .isFalse(); |
| } |
| |
| @Test |
| public void resetMediaAudioOnPrimaryZone_afterAllowed() throws Exception { |
| mCarAudioService.init(); |
| TestPrimaryZoneMediaAudioRequestCallback |
| requestToken = new TestPrimaryZoneMediaAudioRequestCallback(); |
| TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback(); |
| assignOccupantToAudioZones(); |
| mCarAudioService.registerPrimaryZoneMediaAudioRequestCallback(requestToken); |
| long requestId = mCarAudioService.requestMediaAudioOnPrimaryZone(requestCallback, |
| TEST_REAR_RIGHT_PASSENGER_OCCUPANT); |
| requestToken.waitForCallback(); |
| requestToken.reset(); |
| mCarAudioService.allowMediaAudioOnPrimaryZone(requestToken, requestId, |
| /* allowed= */ true); |
| requestToken.waitForCallback(); |
| requestToken.reset(); |
| |
| boolean reset = mCarAudioService.resetMediaAudioOnPrimaryZone( |
| TEST_REAR_RIGHT_PASSENGER_OCCUPANT); |
| |
| requestToken.waitForCallback(); |
| expectWithMessage("Reset status").that(reset).isTrue(); |
| expectWithMessage("Media reset status") |
| .that(mCarAudioService.isMediaAudioAllowedInPrimaryZone( |
| TEST_REAR_RIGHT_PASSENGER_OCCUPANT)) |
| .isFalse(); |
| } |
| |
| @Test |
| public void cancelMediaAudioOnPrimaryZone_beforeAllowed() throws Exception { |
| mCarAudioService.init(); |
| TestPrimaryZoneMediaAudioRequestCallback |
| requestToken = new TestPrimaryZoneMediaAudioRequestCallback(); |
| TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback(); |
| assignOccupantToAudioZones(); |
| mCarAudioService.registerPrimaryZoneMediaAudioRequestCallback(requestToken); |
| long requestId = mCarAudioService.requestMediaAudioOnPrimaryZone(requestCallback, |
| TEST_REAR_RIGHT_PASSENGER_OCCUPANT); |
| requestToken.waitForCallback(); |
| requestToken.reset(); |
| |
| boolean cancel = mCarAudioService.cancelMediaAudioOnPrimaryZone(requestId); |
| |
| requestToken.waitForCallback(); |
| expectWithMessage("Cancel status").that(cancel).isTrue(); |
| expectWithMessage("Canceled media token called audio media request id") |
| .that(requestToken.mRequestId).isEqualTo(requestId); |
| expectWithMessage("Canceled media token called audio media request info") |
| .that(requestToken.mInfo).isEqualTo(TEST_REAR_RIGHT_PASSENGER_OCCUPANT); |
| expectWithMessage("Canceled media token called audio media request status") |
| .that(requestToken.mStatus) |
| .isEqualTo(CarAudioManager.AUDIO_REQUEST_STATUS_CANCELLED); |
| } |
| |
| @Test |
| public void cancelMediaAudioOnPrimaryZone_afterAllowed() throws Exception { |
| mCarAudioService.init(); |
| TestPrimaryZoneMediaAudioRequestCallback |
| requestToken = new TestPrimaryZoneMediaAudioRequestCallback(); |
| TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback(); |
| assignOccupantToAudioZones(); |
| mCarAudioService.registerPrimaryZoneMediaAudioRequestCallback(requestToken); |
| long requestId = mCarAudioService.requestMediaAudioOnPrimaryZone(requestCallback, |
| TEST_REAR_RIGHT_PASSENGER_OCCUPANT); |
| requestToken.waitForCallback(); |
| requestToken.reset(); |
| mCarAudioService.allowMediaAudioOnPrimaryZone(requestToken, requestId, |
| /* allowed= */ true); |
| requestToken.waitForCallback(); |
| requestToken.reset(); |
| |
| boolean cancel = mCarAudioService.cancelMediaAudioOnPrimaryZone(requestId); |
| |
| requestToken.waitForCallback(); |
| expectWithMessage("Cancel status after allowed").that(cancel).isTrue(); |
| expectWithMessage("Media allowed status after canceled") |
| .that(mCarAudioService.isMediaAudioAllowedInPrimaryZone( |
| TEST_REAR_RIGHT_PASSENGER_OCCUPANT)) |
| .isFalse(); |
| } |
| |
| @Test |
| public void getZoneIdForAudioFocusInfo_beforeAllowedSharedAudio() throws Exception { |
| mCarAudioService.init(); |
| TestPrimaryZoneMediaAudioRequestCallback |
| requestToken = new TestPrimaryZoneMediaAudioRequestCallback(); |
| TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback(); |
| assignOccupantToAudioZones(); |
| mCarAudioService.registerPrimaryZoneMediaAudioRequestCallback(requestToken); |
| mCarAudioService.requestMediaAudioOnPrimaryZone(requestCallback, |
| TEST_REAR_RIGHT_PASSENGER_OCCUPANT); |
| requestToken.waitForCallback(); |
| |
| expectWithMessage("Not yet shared media user zone") |
| .that(mCarAudioService.getZoneIdForAudioFocusInfo(TEST_REAR_RIGHT_AUDIO_FOCUS_INFO)) |
| .isEqualTo(TEST_REAR_RIGHT_ZONE_ID); |
| } |
| |
| @Test |
| public void getZoneIdForAudioFocusInfo_afterAllowedShareAudio() throws Exception { |
| mCarAudioService.init(); |
| TestPrimaryZoneMediaAudioRequestCallback |
| requestToken = new TestPrimaryZoneMediaAudioRequestCallback(); |
| TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback(); |
| assignOccupantToAudioZones(); |
| mCarAudioService.registerPrimaryZoneMediaAudioRequestCallback(requestToken); |
| long requestId = mCarAudioService.requestMediaAudioOnPrimaryZone(requestCallback, |
| TEST_REAR_RIGHT_PASSENGER_OCCUPANT); |
| requestToken.waitForCallback(); |
| requestToken.reset(); |
| mCarAudioService.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allowed= */ true); |
| requestToken.waitForCallback(); |
| |
| expectWithMessage("Shared media user zone") |
| .that(mCarAudioService.getZoneIdForAudioFocusInfo(TEST_REAR_RIGHT_AUDIO_FOCUS_INFO)) |
| .isEqualTo(PRIMARY_AUDIO_ZONE); |
| } |
| |
| @Test |
| public void getZoneIdForAudioFocusInfo_afterCanceled() throws Exception { |
| mCarAudioService.init(); |
| TestPrimaryZoneMediaAudioRequestCallback |
| requestToken = new TestPrimaryZoneMediaAudioRequestCallback(); |
| TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback(); |
| assignOccupantToAudioZones(); |
| mCarAudioService.registerPrimaryZoneMediaAudioRequestCallback(requestToken); |
| long requestId = mCarAudioService.requestMediaAudioOnPrimaryZone(requestCallback, |
| TEST_REAR_RIGHT_PASSENGER_OCCUPANT); |
| requestToken.waitForCallback(); |
| requestToken.reset(); |
| mCarAudioService.allowMediaAudioOnPrimaryZone(requestToken, requestId, |
| /* allowed= */ true); |
| requestToken.waitForCallback(); |
| requestToken.reset(); |
| mCarAudioService.cancelMediaAudioOnPrimaryZone(requestId); |
| requestToken.waitForCallback(); |
| |
| expectWithMessage("Canceled shared media user zone") |
| .that(mCarAudioService.getZoneIdForAudioFocusInfo(TEST_REAR_RIGHT_AUDIO_FOCUS_INFO)) |
| .isEqualTo(TEST_REAR_RIGHT_ZONE_ID); |
| } |
| |
| @Test |
| public void getZoneIdForAudioFocusInfo_afterReset() throws Exception { |
| mCarAudioService.init(); |
| TestPrimaryZoneMediaAudioRequestCallback |
| requestToken = new TestPrimaryZoneMediaAudioRequestCallback(); |
| TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback(); |
| assignOccupantToAudioZones(); |
| mCarAudioService.registerPrimaryZoneMediaAudioRequestCallback(requestToken); |
| long requestId = mCarAudioService.requestMediaAudioOnPrimaryZone(requestCallback, |
| TEST_REAR_RIGHT_PASSENGER_OCCUPANT); |
| requestToken.waitForCallback(); |
| requestToken.reset(); |
| mCarAudioService.allowMediaAudioOnPrimaryZone(requestToken, requestId, |
| /* allowed= */ true); |
| requestToken.waitForCallback(); |
| requestToken.reset(); |
| mCarAudioService.resetMediaAudioOnPrimaryZone(TEST_REAR_RIGHT_PASSENGER_OCCUPANT); |
| requestToken.waitForCallback(); |
| |
| expectWithMessage("Reset shared media user zone") |
| .that(mCarAudioService.getZoneIdForAudioFocusInfo(TEST_REAR_RIGHT_AUDIO_FOCUS_INFO)) |
| .isEqualTo(TEST_REAR_RIGHT_ZONE_ID); |
| } |
| |
| private static CarOccupantZoneManager.OccupantZoneInfo getOccupantInfo(int occupantZoneId, |
| int occupantType, int seat) { |
| return new CarOccupantZoneManager.OccupantZoneInfo(occupantZoneId, occupantType, seat); |
| } |
| |
| @Test |
| public void getAudioAttributesForVolumeGroup() { |
| mCarAudioService.init(); |
| CarVolumeGroupInfo info = mCarAudioService.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, |
| TEST_PRIMARY_GROUP); |
| |
| List<AudioAttributes> audioAttributes = |
| mCarAudioService.getAudioAttributesForVolumeGroup(info); |
| |
| expectWithMessage("Volume group audio attributes").that(audioAttributes) |
| .containsExactly( |
| CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA), |
| CarAudioContext.getAudioAttributeFromUsage(USAGE_GAME), |
| CarAudioContext.getAudioAttributeFromUsage(USAGE_UNKNOWN), |
| CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION), |
| CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION_EVENT), |
| CarAudioContext.getAudioAttributeFromUsage(USAGE_ANNOUNCEMENT)); |
| } |
| |
| @Test |
| public void getAudioAttributesForVolumeGroup_withNullInfo_fails() { |
| mCarAudioService.init(); |
| |
| NullPointerException thrown = |
| assertThrows(NullPointerException.class, () -> |
| mCarAudioService.getAudioAttributesForVolumeGroup(/* groupInfo= */ null)); |
| |
| expectWithMessage("Volume group audio attributes with null info exception") |
| .that(thrown).hasMessageThat().contains("Car volume group info"); |
| } |
| |
| @Test |
| public void getAudioAttributesForVolumeGroup_withDynamicRoutingDisabled() { |
| when(mMockResources.getBoolean(audioUseDynamicRouting)) |
| .thenReturn(/* useDynamicRouting= */ false); |
| CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| nonDynamicAudioService.init(); |
| |
| List<AudioAttributes> audioAttributes = |
| nonDynamicAudioService.getAudioAttributesForVolumeGroup(TEST_PRIMARY_VOLUME_INFO); |
| |
| expectWithMessage("Volume group audio attributes with dynamic routing disabled") |
| .that(audioAttributes).isEmpty(); |
| } |
| |
| @Test |
| public void onKeyEvent_forInvalidAudioZone() { |
| mCarAudioService.init(); |
| int volumeBefore = mCarAudioService.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP); |
| CarInputService.KeyEventListener listener = getAudioKeyEventListener(); |
| when(mMockOccupantZoneService.getOccupantZoneIdForSeat(TEST_SEAT)) |
| .thenReturn(PRIMARY_OCCUPANT_ZONE); |
| when(mMockOccupantZoneService.getAudioZoneIdForOccupant(PRIMARY_OCCUPANT_ZONE)) |
| .thenReturn(INVALID_AUDIO_ZONE); |
| KeyEvent keyEvent = new KeyEvent(ACTION_DOWN, KEYCODE_UNKNOWN); |
| |
| listener.onKeyEvent(keyEvent, TEST_DISPLAY_TYPE, TEST_SEAT); |
| |
| expectWithMessage("Volume group volume after invalid audio zone") |
| .that(mCarAudioService.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP)) |
| .isEqualTo(volumeBefore); |
| } |
| |
| @Test |
| public void onKeyEvent_forInvalidEvent() { |
| mCarAudioService.init(); |
| int volumeBefore = mCarAudioService.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP); |
| CarInputService.KeyEventListener listener = getAudioKeyEventListener(); |
| when(mMockOccupantZoneService.getOccupantZoneIdForSeat(TEST_SEAT)) |
| .thenReturn(PRIMARY_OCCUPANT_ZONE); |
| when(mMockOccupantZoneService.getAudioZoneIdForOccupant(PRIMARY_OCCUPANT_ZONE)) |
| .thenReturn(PRIMARY_AUDIO_ZONE); |
| KeyEvent keyEvent = new KeyEvent(ACTION_DOWN, KEYCODE_UNKNOWN); |
| |
| listener.onKeyEvent(keyEvent, TEST_DISPLAY_TYPE, TEST_SEAT); |
| |
| expectWithMessage("Volume group volume after unknown key event") |
| .that(mCarAudioService.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP)) |
| .isEqualTo(volumeBefore); |
| } |
| |
| @Test |
| public void onKeyEvent_forActionUp() { |
| mCarAudioService.init(); |
| int volumeBefore = mCarAudioService.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP); |
| CarInputService.KeyEventListener listener = getAudioKeyEventListener(); |
| when(mMockOccupantZoneService.getOccupantZoneIdForSeat(TEST_SEAT)) |
| .thenReturn(PRIMARY_OCCUPANT_ZONE); |
| when(mMockOccupantZoneService.getAudioZoneIdForOccupant(PRIMARY_OCCUPANT_ZONE)) |
| .thenReturn(PRIMARY_AUDIO_ZONE); |
| KeyEvent keyEvent = new KeyEvent(ACTION_UP, KEYCODE_VOLUME_UP); |
| |
| listener.onKeyEvent(keyEvent, TEST_DISPLAY_TYPE, TEST_SEAT); |
| |
| expectWithMessage("Volume group volume after volume up in primary zone in primary group " |
| + "for action up") |
| .that(mCarAudioService.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP)) |
| .isEqualTo(volumeBefore); |
| } |
| |
| @Test |
| public void onKeyEvent_forActionDownFollowedByActionUp() { |
| mCarAudioService.init(); |
| int volumeBefore = mCarAudioService.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP); |
| CarInputService.KeyEventListener listener = getAudioKeyEventListener(); |
| when(mMockOccupantZoneService.getOccupantZoneIdForSeat(TEST_SEAT)) |
| .thenReturn(PRIMARY_OCCUPANT_ZONE); |
| when(mMockOccupantZoneService.getAudioZoneIdForOccupant(PRIMARY_OCCUPANT_ZONE)) |
| .thenReturn(PRIMARY_AUDIO_ZONE); |
| KeyEvent actionDownKeyEvent = new KeyEvent(ACTION_DOWN, KEYCODE_VOLUME_UP); |
| KeyEvent actionUpKeyEvent = new KeyEvent(ACTION_UP, KEYCODE_VOLUME_UP); |
| listener.onKeyEvent(actionDownKeyEvent, TEST_DISPLAY_TYPE, TEST_SEAT); |
| |
| listener.onKeyEvent(actionUpKeyEvent, TEST_DISPLAY_TYPE, TEST_SEAT); |
| |
| expectWithMessage("Volume group volume after volume up in primary zone in primary group " |
| + "for action down then action up") |
| .that(mCarAudioService.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP)) |
| .isEqualTo(volumeBefore + 1); |
| } |
| |
| @Test |
| public void onKeyEvent_forVolumeUpEvent_inPrimaryZone() { |
| mCarAudioService.init(); |
| int volumeBefore = mCarAudioService.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP); |
| CarInputService.KeyEventListener listener = getAudioKeyEventListener(); |
| when(mMockOccupantZoneService.getOccupantZoneIdForSeat(TEST_SEAT)) |
| .thenReturn(PRIMARY_OCCUPANT_ZONE); |
| when(mMockOccupantZoneService.getAudioZoneIdForOccupant(PRIMARY_OCCUPANT_ZONE)) |
| .thenReturn(PRIMARY_AUDIO_ZONE); |
| KeyEvent keyEvent = new KeyEvent(ACTION_DOWN, KEYCODE_VOLUME_UP); |
| |
| listener.onKeyEvent(keyEvent, TEST_DISPLAY_TYPE, TEST_SEAT); |
| |
| expectWithMessage("Volume group volume after volume up in primary zone in primary group") |
| .that(mCarAudioService.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP)) |
| .isGreaterThan(volumeBefore); |
| } |
| |
| @Test |
| public void onKeyEvent_forVolumeDownEvent_inPrimaryZone() { |
| mCarAudioService.init(); |
| int volumeBefore = mCarAudioService.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP); |
| CarInputService.KeyEventListener listener = getAudioKeyEventListener(); |
| when(mMockOccupantZoneService.getOccupantZoneIdForSeat(TEST_SEAT)) |
| .thenReturn(PRIMARY_OCCUPANT_ZONE); |
| when(mMockOccupantZoneService.getAudioZoneIdForOccupant(PRIMARY_OCCUPANT_ZONE)) |
| .thenReturn(PRIMARY_AUDIO_ZONE); |
| KeyEvent keyEvent = new KeyEvent(ACTION_DOWN, KEYCODE_VOLUME_DOWN); |
| |
| listener.onKeyEvent(keyEvent, TEST_DISPLAY_TYPE, TEST_SEAT); |
| |
| expectWithMessage("Volume group volume after volume down in primary zone in primary group") |
| .that(mCarAudioService.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP)) |
| .isLessThan(volumeBefore); |
| } |
| |
| @Test |
| public void onKeyEvent_forVolumeDownEvent_inPrimaryZone_forSecondaryGroup() { |
| mCarAudioService.init(); |
| int volumeBefore = mCarAudioService.getGroupVolume(PRIMARY_AUDIO_ZONE, |
| TEST_SECONDARY_GROUP); |
| AudioPlaybackCallback callback = getCarAudioPlaybackCallback(); |
| callback.onPlaybackConfigChanged(List.of(new AudioPlaybackConfigurationBuilder() |
| .setUsage(USAGE_ASSISTANT) |
| .setDeviceAddress(VOICE_TEST_DEVICE) |
| .build()) |
| ); |
| CarInputService.KeyEventListener listener = getAudioKeyEventListener(); |
| when(mMockOccupantZoneService.getOccupantZoneIdForSeat(TEST_SEAT)) |
| .thenReturn(PRIMARY_OCCUPANT_ZONE); |
| when(mMockOccupantZoneService.getAudioZoneIdForOccupant(PRIMARY_OCCUPANT_ZONE)) |
| .thenReturn(PRIMARY_AUDIO_ZONE); |
| KeyEvent keyEvent = new KeyEvent(ACTION_DOWN, KEYCODE_VOLUME_DOWN); |
| |
| listener.onKeyEvent(keyEvent, TEST_DISPLAY_TYPE, TEST_SEAT); |
| |
| expectWithMessage( |
| "Assistant volume group volume after volume down") |
| .that(mCarAudioService.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_SECONDARY_GROUP)) |
| .isLessThan(volumeBefore); |
| } |
| |
| @Test |
| public void onKeyEvent_forVolumeDownEvent_inPrimaryZone_withHigherPriority() { |
| mCarAudioService.init(); |
| int primaryGroupVolumeBefore = mCarAudioService.getGroupVolume(PRIMARY_AUDIO_ZONE, |
| TEST_PRIMARY_GROUP); |
| int voiceVolumeGroupBefore = mCarAudioService.getGroupVolume(PRIMARY_AUDIO_ZONE, |
| TEST_THIRD_GROUP); |
| AudioPlaybackCallback callback = getCarAudioPlaybackCallback(); |
| callback.onPlaybackConfigChanged(List.of( |
| new AudioPlaybackConfigurationBuilder() |
| .setUsage(USAGE_VOICE_COMMUNICATION) |
| .setDeviceAddress(CALL_TEST_DEVICE) |
| .build(), |
| new AudioPlaybackConfigurationBuilder() |
| .setUsage(USAGE_MEDIA) |
| .setDeviceAddress(MEDIA_TEST_DEVICE) |
| .build()) |
| ); |
| CarInputService.KeyEventListener listener = getAudioKeyEventListener(); |
| when(mMockOccupantZoneService.getOccupantZoneIdForSeat(TEST_SEAT)) |
| .thenReturn(PRIMARY_OCCUPANT_ZONE); |
| when(mMockOccupantZoneService.getAudioZoneIdForOccupant(PRIMARY_OCCUPANT_ZONE)) |
| .thenReturn(PRIMARY_AUDIO_ZONE); |
| KeyEvent keyEvent = new KeyEvent(ACTION_DOWN, KEYCODE_VOLUME_DOWN); |
| |
| listener.onKeyEvent(keyEvent, TEST_DISPLAY_TYPE, TEST_SEAT); |
| |
| expectWithMessage("Media volume group volume after volume down") |
| .that(mCarAudioService.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP)) |
| .isEqualTo(primaryGroupVolumeBefore); |
| expectWithMessage("Call volume group volume after volume do") |
| .that(mCarAudioService.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_THIRD_GROUP)) |
| .isLessThan(voiceVolumeGroupBefore); |
| } |
| |
| @Test |
| public void onKeyEvent_forVolumeMuteEvent_inPrimaryZone() { |
| mCarAudioService.init(); |
| boolean muteBefore = mCarAudioService.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE, |
| TEST_PRIMARY_GROUP); |
| CarInputService.KeyEventListener listener = getAudioKeyEventListener(); |
| when(mMockOccupantZoneService.getOccupantZoneIdForSeat(TEST_SEAT)) |
| .thenReturn(PRIMARY_OCCUPANT_ZONE); |
| when(mMockOccupantZoneService.getAudioZoneIdForOccupant(PRIMARY_OCCUPANT_ZONE)) |
| .thenReturn(PRIMARY_AUDIO_ZONE); |
| KeyEvent keyEvent = new KeyEvent(ACTION_DOWN, KEYCODE_VOLUME_MUTE); |
| |
| listener.onKeyEvent(keyEvent, TEST_DISPLAY_TYPE, TEST_SEAT); |
| |
| expectWithMessage("Volume group volume after volume mute") |
| .that(mCarAudioService.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP)) |
| .isNotEqualTo(muteBefore); |
| } |
| |
| @Test |
| public void onKeyEvent_forVolumeUpEvent_inSecondaryZone() { |
| mCarAudioService.init(); |
| int volumeBefore = mCarAudioService.getGroupVolume(TEST_REAR_LEFT_ZONE_ID, |
| SECONDARY_ZONE_VOLUME_GROUP_ID); |
| CarInputService.KeyEventListener listener = getAudioKeyEventListener(); |
| when(mMockOccupantZoneService.getOccupantZoneIdForSeat(TEST_SEAT)) |
| .thenReturn(TEST_DRIVER_OCCUPANT_ZONE_ID); |
| when(mMockOccupantZoneService.getAudioZoneIdForOccupant(TEST_DRIVER_OCCUPANT_ZONE_ID)) |
| .thenReturn(TEST_REAR_LEFT_ZONE_ID); |
| KeyEvent keyEvent = new KeyEvent(ACTION_DOWN, KEYCODE_VOLUME_UP); |
| |
| listener.onKeyEvent(keyEvent, TEST_DISPLAY_TYPE, TEST_SEAT); |
| |
| expectWithMessage("Secondary zone volume group after volume up") |
| .that(mCarAudioService.getGroupVolume(TEST_REAR_LEFT_ZONE_ID, |
| SECONDARY_ZONE_VOLUME_GROUP_ID)) |
| .isGreaterThan(volumeBefore); |
| } |
| |
| @Test |
| public void onKeyEvent_forVolumeDownEvent_inSecondaryZone() { |
| mCarAudioService.init(); |
| int volumeBefore = mCarAudioService.getGroupVolume(TEST_REAR_LEFT_ZONE_ID, |
| SECONDARY_ZONE_VOLUME_GROUP_ID); |
| CarInputService.KeyEventListener listener = getAudioKeyEventListener(); |
| when(mMockOccupantZoneService.getOccupantZoneIdForSeat(TEST_SEAT)) |
| .thenReturn(TEST_DRIVER_OCCUPANT_ZONE_ID); |
| when(mMockOccupantZoneService.getAudioZoneIdForOccupant(TEST_DRIVER_OCCUPANT_ZONE_ID)) |
| .thenReturn(TEST_REAR_LEFT_ZONE_ID); |
| KeyEvent keyEvent = new KeyEvent(ACTION_DOWN, KEYCODE_VOLUME_DOWN); |
| |
| listener.onKeyEvent(keyEvent, TEST_DISPLAY_TYPE, TEST_SEAT); |
| |
| expectWithMessage("Secondary zone volume group after volume down") |
| .that(mCarAudioService.getGroupVolume(TEST_REAR_LEFT_ZONE_ID, |
| SECONDARY_ZONE_VOLUME_GROUP_ID)) |
| .isLessThan(volumeBefore); |
| } |
| |
| @Test |
| public void onKeyEvent_forVolumeMuteEvent_inSecondaryZone() { |
| mCarAudioService.init(); |
| boolean muteBefore = mCarAudioService.isVolumeGroupMuted(TEST_REAR_LEFT_ZONE_ID, |
| SECONDARY_ZONE_VOLUME_GROUP_ID); |
| CarInputService.KeyEventListener listener = getAudioKeyEventListener(); |
| when(mMockOccupantZoneService.getOccupantZoneIdForSeat(TEST_SEAT)) |
| .thenReturn(TEST_DRIVER_OCCUPANT_ZONE_ID); |
| when(mMockOccupantZoneService.getAudioZoneIdForOccupant(TEST_DRIVER_OCCUPANT_ZONE_ID)) |
| .thenReturn(TEST_REAR_LEFT_ZONE_ID); |
| KeyEvent keyEvent = new KeyEvent(ACTION_DOWN, KEYCODE_VOLUME_MUTE); |
| |
| listener.onKeyEvent(keyEvent, TEST_DISPLAY_TYPE, TEST_SEAT); |
| |
| expectWithMessage("Secondary zone volume group after volume mute") |
| .that(mCarAudioService.isVolumeGroupMuted(TEST_REAR_LEFT_ZONE_ID, |
| SECONDARY_ZONE_VOLUME_GROUP_ID)) |
| .isNotEqualTo(muteBefore); |
| } |
| |
| @Test |
| public void onAudioDeviceGainsChanged_forPrimaryZone_changesVolume() { |
| mCarAudioService.init(); |
| HalAudioGainCallback callback = getHalAudioGainCallback(); |
| CarAudioGainConfigInfo carGain = createCarAudioGainConfigInfo(PRIMARY_AUDIO_ZONE, |
| MEDIA_TEST_DEVICE, TEST_GAIN_INDEX); |
| |
| callback.onAudioDeviceGainsChanged(List.of(Reasons.REMOTE_MUTE), List.of(carGain)); |
| |
| expectWithMessage("New audio gains for primary zone") |
| .that(mCarAudioService.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP)) |
| .isEqualTo(TEST_GAIN_INDEX); |
| } |
| |
| @Test |
| public void onAudioDeviceGainsChanged_forSecondaryZone_changesVolume() { |
| mCarAudioService.init(); |
| HalAudioGainCallback callback = getHalAudioGainCallback(); |
| CarAudioGainConfigInfo carGain = createCarAudioGainConfigInfo(TEST_REAR_LEFT_ZONE_ID, |
| SECONDARY_TEST_DEVICE_1, TEST_GAIN_INDEX); |
| |
| callback.onAudioDeviceGainsChanged(List.of(Reasons.REMOTE_MUTE), List.of(carGain)); |
| |
| expectWithMessage("New audio gains for secondary zone") |
| .that(mCarAudioService.getGroupVolume(TEST_REAR_LEFT_ZONE_ID, TEST_PRIMARY_GROUP)) |
| .isEqualTo(TEST_GAIN_INDEX); |
| } |
| |
| @Test |
| public void onAudioDeviceGainsChanged_forIncorrectDeviceAddress_sameVolume() { |
| mCarAudioService.init(); |
| HalAudioGainCallback callback = getHalAudioGainCallback(); |
| int volumeBefore = mCarAudioService.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP); |
| CarAudioGainConfigInfo carGain = createCarAudioGainConfigInfo(PRIMARY_AUDIO_ZONE, |
| SECONDARY_TEST_DEVICE_1, TEST_GAIN_INDEX); |
| |
| callback.onAudioDeviceGainsChanged(List.of(Reasons.REMOTE_MUTE), List.of(carGain)); |
| |
| expectWithMessage("Same audio gains for primary zone") |
| .that(mCarAudioService.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP)) |
| .isEqualTo(volumeBefore); |
| } |
| |
| @Test |
| public void onAudioDeviceGainsChanged_forMultipleZones_changesVolume() { |
| mCarAudioService.init(); |
| HalAudioGainCallback callback = getHalAudioGainCallback(); |
| CarAudioGainConfigInfo primaryAudioZoneCarGain = createCarAudioGainConfigInfo( |
| PRIMARY_AUDIO_ZONE, MEDIA_TEST_DEVICE, TEST_GAIN_INDEX); |
| CarAudioGainConfigInfo secondaryAudioZoneCarGain = createCarAudioGainConfigInfo( |
| TEST_REAR_LEFT_ZONE_ID, SECONDARY_TEST_DEVICE_1, TEST_GAIN_INDEX); |
| |
| callback.onAudioDeviceGainsChanged(List.of(Reasons.THERMAL_LIMITATION), |
| List.of(primaryAudioZoneCarGain, secondaryAudioZoneCarGain)); |
| |
| expectWithMessage("New audio gains for primary zone") |
| .that(mCarAudioService.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP)) |
| .isEqualTo(TEST_GAIN_INDEX); |
| expectWithMessage("New audio gains for secondary zone") |
| .that(mCarAudioService.getGroupVolume(TEST_REAR_LEFT_ZONE_ID, TEST_PRIMARY_GROUP)) |
| .isEqualTo(TEST_GAIN_INDEX); |
| } |
| |
| @Test |
| public void onAudioPortsChanged_forMediaBus_changesVolumeRanges() { |
| mCarAudioService.init(); |
| HalAudioModuleChangeCallback callback = getHalModuleChangeCallback(); |
| HalAudioDeviceInfo mediaBusDeviceInfo = createHalAudioDeviceInfo( |
| TEST_MEDIA_PORT_ID, TEST_MEDIA_PORT_NAME, TEST_GAIN_MIN_VALUE, TEST_GAIN_MAX_VALUE, |
| TEST_GAIN_DEFAULT_VALUE, TEST_GAIN_STEP_VALUE, OUT_DEVICE, MEDIA_TEST_DEVICE); |
| CarVolumeGroupInfo volumeGroupInfoBefore = |
| mCarAudioService.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP); |
| |
| callback.onAudioPortsChanged(List.of(mediaBusDeviceInfo)); |
| |
| expectWithMessage("update audio port for media device") |
| .that(mCarAudioService.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP)) |
| .isNotEqualTo(volumeGroupInfoBefore); |
| } |
| |
| @Test |
| public void onAudioPortsChanged_forNavBus_changesVolumeRanges() { |
| mCarAudioService.init(); |
| HalAudioModuleChangeCallback callback = getHalModuleChangeCallback(); |
| HalAudioDeviceInfo navBusDeviceInfo = createHalAudioDeviceInfo( |
| TEST_NAV_PORT_ID, TEST_NAV_PORT_NAME, TEST_GAIN_MIN_VALUE, TEST_GAIN_MAX_VALUE, |
| TEST_GAIN_DEFAULT_VALUE, TEST_GAIN_STEP_VALUE, OUT_DEVICE, NAVIGATION_TEST_DEVICE); |
| CarVolumeGroupInfo volumeGroupInfoBefore = |
| mCarAudioService.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, TEST_SECONDARY_GROUP); |
| |
| callback.onAudioPortsChanged(List.of(navBusDeviceInfo)); |
| |
| expectWithMessage("update audio port for nav device") |
| .that(mCarAudioService.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, TEST_SECONDARY_GROUP)) |
| .isNotEqualTo(volumeGroupInfoBefore); |
| } |
| |
| @Test |
| public void onAudioPortsChanged_forMultipleBuses_changesVolumeRanges() { |
| mCarAudioService.init(); |
| HalAudioModuleChangeCallback callback = getHalModuleChangeCallback(); |
| HalAudioDeviceInfo mediaBusDeviceInfo = createHalAudioDeviceInfo( |
| TEST_MEDIA_PORT_ID, TEST_MEDIA_PORT_NAME, TEST_GAIN_MIN_VALUE, TEST_GAIN_MAX_VALUE, |
| TEST_GAIN_DEFAULT_VALUE, TEST_GAIN_STEP_VALUE, OUT_DEVICE, MEDIA_TEST_DEVICE); |
| HalAudioDeviceInfo navBusDeviceInfo = createHalAudioDeviceInfo( |
| TEST_NAV_PORT_ID, TEST_NAV_PORT_NAME, TEST_GAIN_MIN_VALUE, TEST_GAIN_MAX_VALUE, |
| TEST_GAIN_DEFAULT_VALUE, TEST_GAIN_STEP_VALUE, OUT_DEVICE, NAVIGATION_TEST_DEVICE); |
| CarVolumeGroupInfo mediaVolumeGroupInfoBefore = |
| mCarAudioService.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP); |
| CarVolumeGroupInfo navVolumeGroupInfoBefore = |
| mCarAudioService.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, TEST_SECONDARY_GROUP); |
| |
| callback.onAudioPortsChanged(List.of(mediaBusDeviceInfo, navBusDeviceInfo)); |
| |
| expectWithMessage("update audio port for media device") |
| .that(mCarAudioService.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_GROUP)) |
| .isNotEqualTo(mediaVolumeGroupInfoBefore); |
| expectWithMessage("update audio port for nav device") |
| .that(mCarAudioService.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, TEST_SECONDARY_GROUP)) |
| .isNotEqualTo(navVolumeGroupInfoBefore); |
| } |
| |
| @Test |
| public void getActiveAudioAttributesForZone() { |
| mCarAudioService.init(); |
| |
| expectWithMessage("Default active audio attributes").that( |
| mCarAudioService.getActiveAudioAttributesForZone(PRIMARY_AUDIO_ZONE)).isEmpty(); |
| } |
| |
| @Test |
| public void getActiveAudioAttributesForZone_withActiveHalFocus() { |
| when(mAudioManager.requestAudioFocus(any())).thenReturn( |
| AudioManager.AUDIOFOCUS_REQUEST_GRANTED); |
| mCarAudioService.init(); |
| requestHalAudioFocus(USAGE_ALARM); |
| |
| expectWithMessage("HAL active audio attributes") |
| .that(mCarAudioService.getActiveAudioAttributesForZone(PRIMARY_AUDIO_ZONE)) |
| .containsExactly(new AudioAttributes.Builder().setUsage(USAGE_ALARM).build()); |
| } |
| |
| @Test |
| public void getActiveAudioAttributesForZone_withActivePlayback() { |
| mCarAudioService.init(); |
| mockActivePlayback(); |
| |
| expectWithMessage("Playback active audio attributes") |
| .that(mCarAudioService.getActiveAudioAttributesForZone(PRIMARY_AUDIO_ZONE)) |
| .containsExactly(new AudioAttributes.Builder().setUsage(USAGE_MEDIA).build()); |
| } |
| |
| @Test |
| public void getActiveAudioAttributesForZone_withActiveHalAndPlayback() { |
| mCarAudioService.init(); |
| mockActivePlayback(); |
| when(mAudioManager.requestAudioFocus(any())).thenReturn( |
| AudioManager.AUDIOFOCUS_REQUEST_GRANTED); |
| requestHalAudioFocus(USAGE_VOICE_COMMUNICATION); |
| |
| expectWithMessage("Playback active audio attributes") |
| .that(mCarAudioService.getActiveAudioAttributesForZone(PRIMARY_AUDIO_ZONE)) |
| .containsExactly(new AudioAttributes.Builder().setUsage(USAGE_MEDIA).build(), |
| new AudioAttributes.Builder().setUsage(USAGE_VOICE_COMMUNICATION).build()); |
| } |
| |
| @Test |
| public void getCallStateForZone_forPrimaryZone() throws Exception { |
| when(mMockTelephonyManager.getCallState()).thenReturn(TelephonyManager.CALL_STATE_OFFHOOK); |
| when(mMockOccupantZoneService.getDriverUserId()).thenReturn(TEST_DRIVER_USER_ID); |
| mCarAudioService.init(); |
| when(mMockOccupantZoneService.getUserForOccupant(anyInt())) |
| .thenReturn(TEST_DRIVER_USER_ID, TEST_REAR_RIGHT_USER_ID); |
| assignOccupantToAudioZones(); |
| |
| expectWithMessage("Primary zone call state").that( |
| mCarAudioService.getCallStateForZone(PRIMARY_AUDIO_ZONE)) |
| .isEqualTo(TelephonyManager.CALL_STATE_OFFHOOK); |
| } |
| |
| @Test |
| public void getCallStateForZone_forNonPrimaryZone() throws Exception { |
| when(mMockTelephonyManager.getCallState()).thenReturn(TelephonyManager.CALL_STATE_OFFHOOK); |
| when(mMockOccupantZoneService.getDriverUserId()).thenReturn(TEST_DRIVER_USER_ID); |
| mCarAudioService.init(); |
| when(mMockOccupantZoneService.getUserForOccupant(anyInt())) |
| .thenReturn(TEST_REAR_LEFT_USER_ID, TEST_REAR_RIGHT_USER_ID); |
| assignOccupantToAudioZones(); |
| |
| expectWithMessage("Secondary zone call state").that( |
| mCarAudioService.getCallStateForZone(TEST_REAR_LEFT_ZONE_ID)) |
| .isEqualTo(TelephonyManager.CALL_STATE_IDLE); |
| } |
| |
| @Test |
| public void getVolumeGroupAndContextCount() { |
| CarAudioService useCoreAudioCarAudioService = |
| getCarAudioServiceUsingCoreAudioRoutingAndVolume(); |
| |
| verify(mAudioManager).registerVolumeGroupCallback(any(), any()); |
| expectWithMessage("Primary zone car volume group count") |
| .that(useCoreAudioCarAudioService.getVolumeGroupCount(PRIMARY_AUDIO_ZONE)) |
| .isEqualTo(CoreAudioRoutingUtils.getVolumeGroups().size()); |
| expectWithMessage("Number of contexts") |
| .that(useCoreAudioCarAudioService.getCarAudioContext().getAllContextsIds().size()) |
| .isEqualTo(CoreAudioRoutingUtils.getProductStrategies().size()); |
| expectWithMessage("Car Audio Contexts") |
| .that(useCoreAudioCarAudioService.getCarAudioContext().getAllContextsIds()) |
| .containsExactly(CoreAudioRoutingUtils.NAV_STRATEGY_ID, |
| CoreAudioRoutingUtils.MUSIC_STRATEGY_ID, |
| CoreAudioRoutingUtils.OEM_STRATEGY_ID); |
| } |
| |
| @Test |
| public void registerAudioZonesMirrorStatusCallback() { |
| mCarAudioService.init(); |
| TestAudioZonesMirrorStatusCallbackCallback callback = |
| new TestAudioZonesMirrorStatusCallbackCallback(/* count= */ 1); |
| |
| boolean registered = mCarAudioService.registerAudioZonesMirrorStatusCallback(callback); |
| |
| expectWithMessage("Audio zones mirror status callback registered status") |
| .that(registered).isTrue(); |
| } |
| |
| @Test |
| public void registerAudioZonesMirrorStatusCallback_withoutMirroringEnabled() { |
| CarAudioService carAudioService = getCarAudioServiceWithoutMirroring(); |
| carAudioService.init(); |
| TestAudioZonesMirrorStatusCallbackCallback callback = |
| new TestAudioZonesMirrorStatusCallbackCallback(/* count= */ 1); |
| |
| IllegalStateException thrown = |
| assertThrows(IllegalStateException.class, () -> |
| carAudioService.registerAudioZonesMirrorStatusCallback(callback)); |
| |
| expectWithMessage("Disabled audio zones mirror register exception").that(thrown) |
| .hasMessageThat().contains("Audio zones mirroring is required"); |
| } |
| |
| @Test |
| public void registerAudioZonesMirrorStatusCallback_withNullCallback() { |
| mCarAudioService.init(); |
| |
| NullPointerException thrown = |
| assertThrows(NullPointerException.class, () -> |
| mCarAudioService.registerAudioZonesMirrorStatusCallback(/* callback= */ null)); |
| |
| expectWithMessage("Null audio zones mirror register exception").that(thrown) |
| .hasMessageThat().contains("Audio zones mirror status callback"); |
| } |
| |
| @Test |
| public void unregisterAudioZonesMirrorStatusCallback_withNullCallback() { |
| mCarAudioService.init(); |
| |
| NullPointerException thrown = |
| assertThrows(NullPointerException.class, () -> mCarAudioService |
| .unregisterAudioZonesMirrorStatusCallback(/* callback= */ null)); |
| |
| expectWithMessage("Null audio zones mirror unregister exception").that(thrown) |
| .hasMessageThat().contains("Audio zones mirror status callback"); |
| } |
| |
| @Test |
| public void enableMirrorForAudioZones_withNullAudioZones() { |
| mCarAudioService.init(); |
| |
| NullPointerException thrown = |
| assertThrows(NullPointerException.class, () -> |
| mCarAudioService.enableMirrorForAudioZones(/* audioZones= */ null)); |
| |
| expectWithMessage("Null mirror audio zones exception").that(thrown) |
| .hasMessageThat().contains("Mirror audio zones"); |
| } |
| |
| @Test |
| public void enableMirrorForAudioZones() throws Exception { |
| mCarAudioService.init(); |
| TestAudioZonesMirrorStatusCallbackCallback callback = |
| getAudioZonesMirrorStatusCallback(); |
| assignOccupantToAudioZones(); |
| |
| mCarAudioService.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES); |
| |
| callback.waitForCallback(); |
| expectWithMessage("Audio mirror approved status").that(callback.getLastStatus()) |
| .isEqualTo(CarAudioManager.AUDIO_REQUEST_STATUS_APPROVED); |
| expectWithMessage("Audio mirror approved zones").that(callback.getLastZoneIds()) |
| .asList().containsExactly(TEST_REAR_LEFT_ZONE_ID, TEST_REAR_RIGHT_ZONE_ID); |
| } |
| |
| @Test |
| public void enableMirrorForAudioZones_forPrimaryZone_fails() throws Exception { |
| mCarAudioService.init(); |
| assignOccupantToAudioZones(); |
| int[] audioZones = new int[]{TEST_REAR_LEFT_ZONE_ID, PRIMARY_AUDIO_ZONE}; |
| |
| IllegalArgumentException thrown = |
| assertThrows(IllegalArgumentException.class, () -> |
| mCarAudioService.enableMirrorForAudioZones(audioZones)); |
| |
| expectWithMessage("Mirror audio zones with primary zone exception").that(thrown) |
| .hasMessageThat().contains("not allowed for primary audio zone"); |
| } |
| |
| @Test |
| public void enableMirrorForAudioZones_forNonAssignedZone_fails() throws Exception { |
| when(mMockOccupantZoneService.getUserForOccupant(TEST_REAR_RIGHT_OCCUPANT_ZONE_ID)) |
| .thenReturn(UserManagerHelper.USER_NULL); |
| mCarAudioService.init(); |
| getAudioZonesMirrorStatusCallback(); |
| assignOccupantToAudioZones(); |
| |
| IllegalStateException thrown = |
| assertThrows(IllegalStateException.class, () -> |
| mCarAudioService.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES)); |
| |
| expectWithMessage("Mirror audio zones for unoccupied audio zone exception") |
| .that(thrown).hasMessageThat().contains("must have an active user"); |
| } |
| |
| @Test |
| public void enableMirrorForAudioZones_forRepeatingZones_fails() throws Exception { |
| mCarAudioService.init(); |
| assignOccupantToAudioZones(); |
| int[] audioZones = new int[]{TEST_REAR_LEFT_ZONE_ID, |
| TEST_REAR_LEFT_ZONE_ID}; |
| |
| IllegalArgumentException thrown = |
| assertThrows(IllegalArgumentException.class, () -> |
| mCarAudioService.enableMirrorForAudioZones(audioZones)); |
| |
| expectWithMessage("Repeated mirror audio zones exception").that(thrown) |
| .hasMessageThat().contains("must be unique"); |
| } |
| |
| @Test |
| public void enableMirrorForAudioZones_forAlreadyMirroredZones() throws Exception { |
| mCarAudioService.init(); |
| TestAudioZonesMirrorStatusCallbackCallback callback = |
| getAudioZonesMirrorStatusCallback(); |
| assignOccupantToAudioZones(); |
| mCarAudioService.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES); |
| callback.waitForCallback(); |
| callback.reset(/* count= */ 1); |
| |
| IllegalStateException thrown = |
| assertThrows(IllegalStateException.class, () -> |
| mCarAudioService.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES)); |
| |
| expectWithMessage("Audio mirror exception for repeating request") |
| .that(thrown).hasMessageThat().contains("is already mirroring"); |
| |
| } |
| |
| @Test |
| public void enableMirrorForAudioZones_afterSharedInPrimaryZone() throws Exception { |
| mCarAudioService.init(); |
| TestPrimaryZoneMediaAudioRequestCallback |
| requestToken = new TestPrimaryZoneMediaAudioRequestCallback(); |
| mCarAudioService.registerPrimaryZoneMediaAudioRequestCallback(requestToken); |
| TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback(); |
| assignOccupantToAudioZones(); |
| long requestId = mCarAudioService.requestMediaAudioOnPrimaryZone(requestCallback, |
| TEST_REAR_RIGHT_PASSENGER_OCCUPANT); |
| requestToken.waitForCallback(); |
| requestToken.reset(); |
| mCarAudioService.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allowed= */ true); |
| requestToken.waitForCallback(); |
| requestToken.reset(); |
| |
| IllegalStateException thrown = |
| assertThrows(IllegalStateException.class, () -> |
| mCarAudioService.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES)); |
| |
| expectWithMessage("Mirror audio zones while sharing in primary zone exception") |
| .that(thrown).hasMessageThat().contains("currently sharing to primary zone"); |
| } |
| |
| @Test |
| public void enableMirrorForAudioZones_forInvertedMirrorConfiguration() |
| throws Exception { |
| mCarAudioService.init(); |
| TestAudioZonesMirrorStatusCallbackCallback callback = |
| getAudioZonesMirrorStatusCallback(); |
| assignOccupantToAudioZones(); |
| mCarAudioService.enableMirrorForAudioZones(new int[] {TEST_REAR_RIGHT_ZONE_ID, |
| TEST_REAR_LEFT_ZONE_ID}); |
| callback.waitForCallback(); |
| callback.reset(/* count= */ 1); |
| |
| IllegalStateException thrown = |
| assertThrows(IllegalStateException.class, () -> |
| mCarAudioService.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES)); |
| |
| expectWithMessage("Audio mirror exception for inverted zone request") |
| .that(thrown).hasMessageThat().contains("is already mirroring"); |
| } |
| |
| @Test |
| public void extendAudioMirrorRequest() throws Exception { |
| mCarAudioService.init(); |
| TestAudioZonesMirrorStatusCallbackCallback callback = |
| getAudioZonesMirrorStatusCallback(); |
| assignOccupantToAudioZones(); |
| long requestId = mCarAudioService.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES); |
| callback.waitForCallback(); |
| callback.reset(1); |
| |
| mCarAudioService.extendAudioMirrorRequest(requestId, new int[] {TEST_FRONT_ZONE_ID}); |
| |
| callback.waitForCallback(); |
| expectWithMessage("Audio mirror approved status").that(callback.getLastStatus()) |
| .isEqualTo(CarAudioManager.AUDIO_REQUEST_STATUS_APPROVED); |
| expectWithMessage("Audio mirror approved zones").that(callback.getLastZoneIds()) |
| .asList().containsExactly(TEST_REAR_LEFT_ZONE_ID, TEST_REAR_RIGHT_ZONE_ID, |
| TEST_FRONT_ZONE_ID); |
| } |
| |
| @Test |
| public void extendAudioMirrorRequest_withNullAudioZones() throws Exception { |
| mCarAudioService.init(); |
| TestAudioZonesMirrorStatusCallbackCallback callback = |
| getAudioZonesMirrorStatusCallback(); |
| assignOccupantToAudioZones(); |
| long requestId = mCarAudioService.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES); |
| callback.waitForCallback(); |
| callback.reset(1); |
| |
| NullPointerException thrown = |
| assertThrows(NullPointerException.class, () -> |
| mCarAudioService.extendAudioMirrorRequest(requestId, |
| /* audioZones = */ null)); |
| |
| expectWithMessage("Null audio zones to extend for mirror request exception") |
| .that(thrown).hasMessageThat().contains("Mirror audio zones"); |
| } |
| |
| @Test |
| public void extendAudioMirrorRequest_withPrimaryAudioZone() throws Exception { |
| mCarAudioService.init(); |
| TestAudioZonesMirrorStatusCallbackCallback callback = |
| getAudioZonesMirrorStatusCallback(); |
| assignOccupantToAudioZones(); |
| long requestId = mCarAudioService.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES); |
| callback.waitForCallback(); |
| callback.reset(1); |
| |
| IllegalArgumentException thrown = |
| assertThrows(IllegalArgumentException.class, () -> |
| mCarAudioService.extendAudioMirrorRequest(requestId, |
| new int[] {PRIMARY_AUDIO_ZONE})); |
| |
| expectWithMessage("Primary audio zone to extend for mirror request exception") |
| .that(thrown).hasMessageThat().contains( |
| "Audio mirroring not allowed for primary audio zone"); |
| } |
| |
| @Test |
| public void getAudioZoneConfigInfos() { |
| mCarAudioService.init(); |
| |
| List<CarAudioZoneConfigInfo> zoneConfigInfos = |
| mCarAudioService.getAudioZoneConfigInfos(TEST_REAR_LEFT_ZONE_ID); |
| |
| List<String> zoneConfigNames = new ArrayList(zoneConfigInfos.size()); |
| for (int index = 0; index < zoneConfigInfos.size(); index++) { |
| zoneConfigNames.add(zoneConfigInfos.get(index).getName()); |
| } |
| expectWithMessage("Zone configurations for secondary zone").that(zoneConfigNames) |
| .containsExactly(SECONDARY_ZONE_CONFIG_NAME_1, SECONDARY_ZONE_CONFIG_NAME_2); |
| } |
| |
| @Test |
| public void getCurrentAudioZoneConfigInfo() { |
| mCarAudioService.init(); |
| |
| CarAudioZoneConfigInfo currentZoneConfigInfo = |
| mCarAudioService.getCurrentAudioZoneConfigInfo(TEST_REAR_LEFT_ZONE_ID); |
| |
| expectWithMessage("Name of current zone configuration for secondary zone") |
| .that(currentZoneConfigInfo.getName()).isEqualTo(SECONDARY_ZONE_CONFIG_NAME_1); |
| } |
| |
| @Test |
| public void switchZoneToConfig() throws Exception { |
| mCarAudioService.init(); |
| SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl(); |
| assignOccupantToAudioZones(); |
| CarAudioZoneConfigInfo zoneConfigSwitchTo = getZoneConfigToSwitch(TEST_REAR_LEFT_ZONE_ID); |
| |
| mCarAudioService.switchZoneToConfig(zoneConfigSwitchTo, callback); |
| |
| callback.waitForCallback(); |
| expectWithMessage("Updated zone configuration") |
| .that(callback.getZoneConfig()).isEqualTo(zoneConfigSwitchTo); |
| expectWithMessage("Zone configuration switching status") |
| .that(callback.getSwitchStatus()).isTrue(); |
| } |
| |
| @Test |
| public void switchZoneToConfig_forNonAssignedZone_fails() throws Exception { |
| when(mMockOccupantZoneService.getUserForOccupant(TEST_REAR_LEFT_OCCUPANT_ZONE_ID)) |
| .thenReturn(UserManagerHelper.USER_NULL); |
| mCarAudioService.init(); |
| SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl(); |
| assignOccupantToAudioZones(); |
| CarAudioZoneConfigInfo zoneConfigSwitchTo = getZoneConfigToSwitch(TEST_REAR_LEFT_ZONE_ID); |
| |
| IllegalStateException thrown = |
| assertThrows(IllegalStateException.class, () -> |
| mCarAudioService.switchZoneToConfig(zoneConfigSwitchTo, callback)); |
| |
| expectWithMessage("Switching zone configuration for unoccupied audio zone exception") |
| .that(thrown).hasMessageThat().contains("must have an active user"); |
| } |
| |
| @Test |
| public void switchZoneToConfig_afterSharedInPrimaryZone_fails() throws Exception { |
| mCarAudioService.init(); |
| SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl(); |
| TestPrimaryZoneMediaAudioRequestCallback |
| requestToken = new TestPrimaryZoneMediaAudioRequestCallback(); |
| mCarAudioService.registerPrimaryZoneMediaAudioRequestCallback(requestToken); |
| TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback(); |
| assignOccupantToAudioZones(); |
| long requestId = mCarAudioService.requestMediaAudioOnPrimaryZone(requestCallback, |
| TEST_REAR_LEFT_PASSENGER_OCCUPANT); |
| requestToken.waitForCallback(); |
| requestToken.reset(); |
| mCarAudioService.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allowed= */ true); |
| requestToken.waitForCallback(); |
| requestToken.reset(); |
| CarAudioZoneConfigInfo zoneConfigSwitchTo = getZoneConfigToSwitch(TEST_REAR_LEFT_ZONE_ID); |
| |
| IllegalStateException thrown = |
| assertThrows(IllegalStateException.class, () -> |
| mCarAudioService.switchZoneToConfig(zoneConfigSwitchTo, callback)); |
| |
| expectWithMessage("Switching zone configuration while sharing in primary zone exception") |
| .that(thrown).hasMessageThat().contains("currently sharing to primary zone"); |
| } |
| |
| @Test |
| public void switchZoneToConfig_afterMirroring_fails() throws Exception { |
| mCarAudioService.init(); |
| SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl(); |
| TestAudioZonesMirrorStatusCallbackCallback mirrorCallback = |
| getAudioZonesMirrorStatusCallback(); |
| assignOccupantToAudioZones(); |
| mCarAudioService.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES); |
| mirrorCallback.waitForCallback(); |
| mirrorCallback.reset(/* count= */ 1); |
| CarAudioZoneConfigInfo zoneConfigSwitchTo = getZoneConfigToSwitch(TEST_REAR_LEFT_ZONE_ID); |
| |
| IllegalStateException thrown = |
| assertThrows(IllegalStateException.class, () -> |
| mCarAudioService.switchZoneToConfig(zoneConfigSwitchTo, callback)); |
| |
| expectWithMessage("Switching zone configuration while audio mirroring").that(thrown) |
| .hasMessageThat().contains("currently in a mirroring configuration"); |
| } |
| |
| @Test |
| public void switchZoneToConfig_withPendingFocus_regainsFocus() throws Exception { |
| mCarAudioService.init(); |
| SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl(); |
| assignOccupantToAudioZones(); |
| AudioFocusInfo audioFocusInfo = createAudioFocusInfoForMedia(TEST_REAR_RIGHT_UID); |
| mCarAudioService.requestAudioFocusForTest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED); |
| CarAudioZoneConfigInfo zoneConfigSwitchTo = getZoneConfigToSwitch(TEST_REAR_RIGHT_ZONE_ID); |
| |
| mCarAudioService.switchZoneToConfig(zoneConfigSwitchTo, callback); |
| |
| callback.waitForCallback(); |
| expectWithMessage("Updated zone configuration with pending focus") |
| .that(callback.getZoneConfig()).isEqualTo(zoneConfigSwitchTo); |
| expectWithMessage("Zone configuration switching status with pending focus") |
| .that(callback.getSwitchStatus()).isTrue(); |
| List<Integer> focusChanges = getFocusChanges(audioFocusInfo); |
| expectWithMessage("Media audio focus changes after switching zone") |
| .that(focusChanges).containsExactly(AUDIOFOCUS_LOSS_TRANSIENT, AUDIOFOCUS_GAIN); |
| } |
| |
| @Test |
| public void switchZoneToConfig_withPendingFocus_updatesDuckingInfo() throws Exception { |
| mCarAudioService.init(); |
| SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl(); |
| assignOccupantToAudioZones(); |
| AudioFocusInfo audioFocusInfo = createAudioFocusInfoForMedia(TEST_REAR_RIGHT_UID); |
| mCarAudioService.requestAudioFocusForTest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED); |
| ArgumentCaptor<List<CarDuckingInfo>> carDuckingInfosCaptor = |
| ArgumentCaptor.forClass(List.class); |
| verify(mAudioControlWrapperAidl).onDevicesToDuckChange(carDuckingInfosCaptor.capture()); |
| verifyMediaDuckingInfoInZone(carDuckingInfosCaptor, TEST_REAR_RIGHT_ZONE_ID, |
| " before switching zone"); |
| CarAudioZoneConfigInfo zoneConfigSwitchTo = getZoneConfigToSwitch(TEST_REAR_RIGHT_ZONE_ID); |
| |
| mCarAudioService.switchZoneToConfig(zoneConfigSwitchTo, callback); |
| |
| callback.waitForCallback(); |
| expectWithMessage("Updated zone configuration with pending focus") |
| .that(callback.getZoneConfig()).isEqualTo(zoneConfigSwitchTo); |
| expectWithMessage("Zone configuration switching status with pending focus") |
| .that(callback.getSwitchStatus()).isTrue(); |
| verify(mAudioControlWrapperAidl, times(2)) |
| .onDevicesToDuckChange(carDuckingInfosCaptor.capture()); |
| verifyMediaDuckingInfoInZone(carDuckingInfosCaptor, TEST_REAR_RIGHT_ZONE_ID, |
| " after switching zone"); |
| } |
| |
| @Test |
| public void switchZoneToConfig_withCurrentZoneConfigAndPendingFocus_notLoseAndRegainFocus() |
| throws Exception { |
| mCarAudioService.init(); |
| SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl(); |
| assignOccupantToAudioZones(); |
| AudioFocusInfo audioFocusInfo = createAudioFocusInfoForMedia(TEST_REAR_RIGHT_UID); |
| mCarAudioService.requestAudioFocusForTest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED); |
| CarAudioZoneConfigInfo currentZoneConfig = |
| mCarAudioService.getCurrentAudioZoneConfigInfo(TEST_REAR_RIGHT_ZONE_ID); |
| |
| mCarAudioService.switchZoneToConfig(currentZoneConfig, callback); |
| |
| callback.waitForCallback(); |
| expectWithMessage("Updated zone configuration with current configuration") |
| .that(callback.getZoneConfig()).isEqualTo(currentZoneConfig); |
| expectWithMessage("Zone configuration switching status with current configuration") |
| .that(callback.getSwitchStatus()).isTrue(); |
| verify(mAudioManager, never()).dispatchAudioFocusChange(eq(audioFocusInfo), anyInt(), |
| any(AudioPolicy.class)); |
| } |
| |
| @Test |
| public void disableAudioMirrorForZone_withInvalidZone() throws Exception { |
| mCarAudioService.init(); |
| assignOccupantToAudioZones(); |
| |
| IllegalArgumentException thrown = |
| assertThrows(IllegalArgumentException.class, () -> |
| mCarAudioService.disableAudioMirrorForZone(INVALID_AUDIO_ZONE)); |
| |
| expectWithMessage("Disable mirror for invalid audio zone exception").that(thrown) |
| .hasMessageThat().contains("Invalid audio zone"); |
| } |
| |
| @Test |
| public void disableAudioMirrorForZone_withoutMirroringDisabled() { |
| CarAudioService carAudioService = getCarAudioServiceWithoutMirroring(); |
| carAudioService.init(); |
| |
| IllegalStateException thrown = |
| assertThrows(IllegalStateException.class, () -> |
| mCarAudioService.disableAudioMirrorForZone(TEST_REAR_LEFT_ZONE_ID)); |
| |
| expectWithMessage("Disable mirror for zone with audio mirroring disabled") |
| .that(thrown).hasMessageThat().contains("Audio zones mirroring is required"); |
| } |
| |
| @Test |
| public void disableAudioMirrorForZone_forNonMirroringZone() throws Exception { |
| mCarAudioService.init(); |
| TestAudioZonesMirrorStatusCallbackCallback callback = |
| getAudioZonesMirrorStatusCallback(); |
| assignOccupantToAudioZones(); |
| |
| mCarAudioService.disableAudioMirrorForZone(TEST_REAR_LEFT_ZONE_ID); |
| |
| callback.waitForCallback(); |
| expectWithMessage("Disable audio mirror for non-mirroring zone callback count") |
| .that(callback.mNumberOfCalls).isEqualTo(0); |
| } |
| |
| @Test |
| public void disableAudioMirrorForZone_forMirroringZones() throws Exception { |
| mCarAudioService.init(); |
| TestAudioZonesMirrorStatusCallbackCallback callback = |
| getAudioZonesMirrorStatusCallback(); |
| assignOccupantToAudioZones(); |
| mCarAudioService.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES); |
| callback.waitForCallback(); |
| callback.reset(/* count= */ 1); |
| |
| mCarAudioService.disableAudioMirrorForZone(TEST_REAR_LEFT_ZONE_ID); |
| |
| callback.waitForCallback(); |
| expectWithMessage("Callback count for disable audio mirror") |
| .that(callback.mNumberOfCalls).isEqualTo(2); |
| expectWithMessage("Callback status disable audio mirror for mirroring zone") |
| .that(callback.getLastStatus()) |
| .isEqualTo(CarAudioManager.AUDIO_REQUEST_STATUS_STOPPED); |
| expectWithMessage("Callback zones disable audio mirror for mirroring zone") |
| .that(callback.getLastZoneIds()).asList() |
| .containsExactly(TEST_REAR_RIGHT_ZONE_ID, TEST_REAR_LEFT_ZONE_ID); |
| } |
| |
| @Test |
| public void disableAudioMirrorForZone_forMirroringZones_forFirstMirroringConfig() |
| throws Exception { |
| mCarAudioService.init(); |
| TestAudioZonesMirrorStatusCallbackCallback callback = |
| getAudioZonesMirrorStatusCallback(); |
| assignOccupantToAudioZones(); |
| mCarAudioService.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES); |
| callback.waitForCallback(); |
| callback.reset(/* count= */ 1); |
| |
| mCarAudioService.disableAudioMirrorForZone(TEST_REAR_RIGHT_ZONE_ID); |
| |
| callback.waitForCallback(); |
| expectWithMessage("Callback count for disable audio mirror") |
| .that(callback.mNumberOfCalls).isEqualTo(2); |
| expectWithMessage("Callback status disable audio mirror for mirroring zone") |
| .that(callback.getLastStatus()) |
| .isEqualTo(CarAudioManager.AUDIO_REQUEST_STATUS_STOPPED); |
| expectWithMessage("Callback zones disable audio mirror for mirroring zone") |
| .that(callback.getLastZoneIds()).asList() |
| .containsExactly(TEST_REAR_RIGHT_ZONE_ID, TEST_REAR_LEFT_ZONE_ID); |
| } |
| |
| @Test |
| public void disableAudioMirrorForZone_withPendingFocus() |
| throws Exception { |
| mCarAudioService.init(); |
| TestAudioZonesMirrorStatusCallbackCallback callback = |
| getAudioZonesMirrorStatusCallback(); |
| assignOccupantToAudioZones(); |
| mCarAudioService.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES); |
| callback.waitForCallback(); |
| callback.reset(/* count= */ 2); |
| AudioFocusInfo audioFocusInfo = createAudioFocusInfoForMedia(TEST_REAR_RIGHT_UID); |
| mCarAudioService.requestAudioFocusForTest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED); |
| |
| mCarAudioService.disableAudioMirrorForZone(TEST_REAR_LEFT_ZONE_ID); |
| |
| callback.waitForCallback(); |
| List<Integer> focusChanges = getFocusChanges(audioFocusInfo); |
| expectWithMessage("Media audio focus changes after disable mirror for zone") |
| .that(focusChanges).containsExactly(AUDIOFOCUS_LOSS_TRANSIENT, AUDIOFOCUS_GAIN); |
| } |
| |
| @Test |
| public void disableAudioMirror_withoutMirroringDisabled() { |
| CarAudioService carAudioService = getCarAudioServiceWithoutMirroring(); |
| carAudioService.init(); |
| |
| IllegalStateException thrown = |
| assertThrows(IllegalStateException.class, () -> |
| carAudioService.disableAudioMirror(INVALID_REQUEST_ID)); |
| |
| expectWithMessage("Disable mirror for audio zones with audio mirroring disabled") |
| .that(thrown).hasMessageThat().contains("Audio zones mirroring is required"); |
| } |
| |
| @Test |
| public void disableAudioMirror_withInvalidRequestId() { |
| mCarAudioService.init(); |
| |
| IllegalArgumentException thrown = |
| assertThrows(IllegalArgumentException.class, () -> |
| mCarAudioService.disableAudioMirror(INVALID_REQUEST_ID)); |
| |
| expectWithMessage("Disable mirror for audio zones with audio invalid request id") |
| .that(thrown).hasMessageThat().contains("INVALID_REQUEST_ID"); |
| } |
| |
| @Test |
| public void disableAudioMirror_forNonMirroringZone() throws Exception { |
| mCarAudioService.init(); |
| TestAudioZonesMirrorStatusCallbackCallback callback = |
| getAudioZonesMirrorStatusCallback(); |
| assignOccupantToAudioZones(); |
| long requestId = mCarAudioService.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES); |
| callback.waitForCallback(); |
| callback.reset(1); |
| mCarAudioService.disableAudioMirror(requestId); |
| callback.waitForCallback(); |
| callback.reset(1); |
| |
| mCarAudioService.disableAudioMirror(requestId); |
| |
| expectWithMessage("Disable audio mirror for non-mirroring zone callback count") |
| .that(callback.mNumberOfCalls).isEqualTo(2); |
| } |
| |
| @Test |
| public void disableAudioMirror_forMirroringZones() throws Exception { |
| mCarAudioService.init(); |
| TestAudioZonesMirrorStatusCallbackCallback callback = |
| getAudioZonesMirrorStatusCallback(); |
| assignOccupantToAudioZones(); |
| long requestId = mCarAudioService.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES); |
| callback.waitForCallback(); |
| callback.reset(/* count= */ 1); |
| |
| mCarAudioService.disableAudioMirror(requestId); |
| |
| callback.waitForCallback(); |
| expectWithMessage("Callback count for disable mirror in audio zones") |
| .that(callback.mNumberOfCalls).isEqualTo(2); |
| expectWithMessage("Callback status disable audio mirror for mirroring zones") |
| .that(callback.getLastStatus()) |
| .isEqualTo(CarAudioManager.AUDIO_REQUEST_STATUS_STOPPED); |
| expectWithMessage("Callback zones disable audio mirror for mirroring zones") |
| .that(callback.getLastZoneIds()).asList() |
| .containsExactly(TEST_REAR_RIGHT_ZONE_ID, TEST_REAR_LEFT_ZONE_ID); |
| } |
| |
| @Test |
| public void disableAudioMirror_withPendingFocus() throws Exception { |
| mCarAudioService.init(); |
| TestAudioZonesMirrorStatusCallbackCallback callback = |
| getAudioZonesMirrorStatusCallback(); |
| assignOccupantToAudioZones(); |
| long requestId = mCarAudioService.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES); |
| callback.waitForCallback(); |
| callback.reset(/* count= */ 2); |
| AudioFocusInfo audioFocusInfo = createAudioFocusInfoForMedia(TEST_REAR_RIGHT_UID); |
| mCarAudioService.requestAudioFocusForTest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED); |
| |
| mCarAudioService.disableAudioMirror(requestId); |
| |
| callback.waitForCallback(); |
| List<Integer> focusChanges = getFocusChanges(audioFocusInfo); |
| expectWithMessage("Media audio focus changes after disable audio" |
| + "mirror for zones config").that(focusChanges) |
| .containsExactly(AUDIOFOCUS_LOSS_TRANSIENT, AUDIOFOCUS_GAIN); |
| } |
| |
| private TestAudioZonesMirrorStatusCallbackCallback getAudioZonesMirrorStatusCallback() { |
| TestAudioZonesMirrorStatusCallbackCallback callback = |
| new TestAudioZonesMirrorStatusCallbackCallback(/* count= */ 1); |
| mCarAudioService.registerAudioZonesMirrorStatusCallback(callback); |
| return callback; |
| } |
| |
| private void assignOccupantToAudioZones() throws RemoteException { |
| ICarOccupantZoneCallback occupantZoneCallback = getOccupantZoneCallback(); |
| occupantZoneCallback.onOccupantZoneConfigChanged( |
| CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER); |
| } |
| |
| private CarAudioGainConfigInfo createCarAudioGainConfigInfo(int zoneId, |
| String devicePortAddress, int volumeIndex) { |
| AudioGainConfigInfo configInfo = new AudioGainConfigInfo(); |
| configInfo.zoneId = zoneId; |
| configInfo.devicePortAddress = devicePortAddress; |
| configInfo.volumeIndex = volumeIndex; |
| return new CarAudioGainConfigInfo(configInfo); |
| } |
| |
| private HalAudioGainCallback getHalAudioGainCallback() { |
| ArgumentCaptor<HalAudioGainCallback> captor = ArgumentCaptor.forClass( |
| HalAudioGainCallback.class); |
| verify(mAudioControlWrapperAidl).registerAudioGainCallback(captor.capture()); |
| return captor.getValue(); |
| } |
| |
| private HalAudioDeviceInfo createHalAudioDeviceInfo(int id, String name, int minVal, |
| int maxVal, int defaultVal, int stepVal, int type, String address) { |
| AudioPortDeviceExt deviceExt = new AudioPortDeviceExt(); |
| deviceExt.device = new AudioDevice(); |
| deviceExt.device.type = new AudioDeviceDescription(); |
| deviceExt.device.type.type = type; |
| deviceExt.device.type.connection = CONNECTION_BUS; |
| deviceExt.device.address = AudioDeviceAddress.id(address); |
| AudioPort audioPort = new AudioPort(); |
| audioPort.id = id; |
| audioPort.name = name; |
| audioPort.gains = new android.media.audio.common.AudioGain[] { |
| new android.media.audio.common.AudioGain() {{ |
| mode = JOINT; |
| minValue = minVal; |
| maxValue = maxVal; |
| defaultValue = defaultVal; |
| stepValue = stepVal; |
| }} |
| }; |
| audioPort.ext = AudioPortExt.device(deviceExt); |
| return new HalAudioDeviceInfo(audioPort); |
| } |
| |
| private HalAudioModuleChangeCallback getHalModuleChangeCallback() { |
| ArgumentCaptor<HalAudioModuleChangeCallback> captor = ArgumentCaptor.forClass( |
| HalAudioModuleChangeCallback.class); |
| verify(mAudioControlWrapperAidl).setModuleChangeCallback(captor.capture()); |
| return captor.getValue(); |
| } |
| |
| private AudioPlaybackCallback getCarAudioPlaybackCallback() { |
| ArgumentCaptor<AudioPlaybackCallback> captor = ArgumentCaptor.forClass( |
| AudioPlaybackCallback.class); |
| verify(mAudioManager).registerAudioPlaybackCallback(captor.capture(), any()); |
| return captor.getValue(); |
| } |
| |
| private CarInputService.KeyEventListener getAudioKeyEventListener() { |
| ArgumentCaptor<CarInputService.KeyEventListener> captor = |
| ArgumentCaptor.forClass(CarInputService.KeyEventListener.class); |
| verify(mMockCarInputService).registerKeyEventListener(captor.capture(), any()); |
| return captor.getValue(); |
| } |
| |
| private void requestHalAudioFocus(int usage) { |
| ArgumentCaptor<HalFocusListener> captor = |
| ArgumentCaptor.forClass(HalFocusListener.class); |
| verify(mAudioControlWrapperAidl).registerFocusListener(captor.capture()); |
| HalFocusListener halFocusListener = captor.getValue(); |
| halFocusListener.requestAudioFocus(usage, PRIMARY_AUDIO_ZONE, |
| AudioManager.AUDIOFOCUS_GAIN_TRANSIENT); |
| } |
| |
| private void mockActivePlayback() { |
| AudioPlaybackCallback callback = getCarAudioPlaybackCallback(); |
| callback.onPlaybackConfigChanged(List.of(getPlaybackConfig())); |
| } |
| |
| private AudioPlaybackConfiguration getPlaybackConfig() { |
| AudioAttributes audioAttributes = new AudioAttributes.Builder() |
| .setUsage(USAGE_MEDIA).build(); |
| AudioPlaybackConfiguration config = mock(AudioPlaybackConfiguration.class); |
| when(config.getAudioAttributes()).thenReturn(audioAttributes); |
| when(config.getAudioDeviceInfo()).thenReturn(mMediaOutputDevice); |
| when(config.isActive()).thenReturn(true); |
| |
| return config; |
| } |
| |
| private CarAudioService getCarAudioServiceWithoutMirroring() { |
| AudioDeviceInfo[] outputDevices = generateOutputDeviceInfos(); |
| when(mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS)).thenReturn(outputDevices); |
| CarAudioService carAudioService = |
| new CarAudioService(mMockContext, mTemporaryAudioConfigurationWithoutMirroringFile |
| .getFile().getAbsolutePath(), mCarVolumeCallbackHandler); |
| carAudioService.init(); |
| return carAudioService; |
| } |
| |
| private CarAudioService getCarAudioServiceUsingCoreAudioRoutingAndVolume() { |
| when(mMockResources.getBoolean(audioUseCoreVolume)) |
| .thenReturn(/* audioUseCoreVolume= */ true); |
| when(mMockResources.getBoolean(audioUseCoreRouting)) |
| .thenReturn(/* audioUseCoreRouting= */ true); |
| CarAudioService useCoreAudioCarAudioService = |
| new CarAudioService(mMockContext, |
| mTemporaryAudioConfigurationUsingCoreAudioFile.getFile().getAbsolutePath(), |
| mCarVolumeCallbackHandler); |
| useCoreAudioCarAudioService.init(); |
| return useCoreAudioCarAudioService; |
| } |
| |
| private void mockGrantCarControlAudioSettingsPermission() { |
| mockContextCheckCallingOrSelfPermission(mMockContext, |
| PERMISSION_CAR_CONTROL_AUDIO_SETTINGS, PERMISSION_GRANTED); |
| } |
| |
| private void mockDenyCarControlAudioSettingsPermission() { |
| mockContextCheckCallingOrSelfPermission(mMockContext, |
| PERMISSION_CAR_CONTROL_AUDIO_SETTINGS, PERMISSION_DENIED); |
| } |
| |
| private void mockDenyCarControlAudioVolumePermission() { |
| mockContextCheckCallingOrSelfPermission(mMockContext, |
| PERMISSION_CAR_CONTROL_AUDIO_VOLUME, PERMISSION_DENIED); |
| } |
| |
| private AudioDeviceInfo[] generateInputDeviceInfos() { |
| mMicrophoneInputDevice = new AudioDeviceInfoBuilder() |
| .setAddressName(PRIMARY_ZONE_MICROPHONE_ADDRESS) |
| .setType(TYPE_BUILTIN_MIC) |
| .setIsSource(true) |
| .build(); |
| mFmTunerInputDevice = new AudioDeviceInfoBuilder() |
| .setAddressName(PRIMARY_ZONE_FM_TUNER_ADDRESS) |
| .setType(TYPE_FM_TUNER) |
| .setIsSource(true) |
| .build(); |
| return new AudioDeviceInfo[]{mMicrophoneInputDevice, mFmTunerInputDevice}; |
| } |
| |
| private AudioDeviceInfo[] generateOutputDeviceInfos() { |
| mMediaOutputDevice = new AudioDeviceInfoBuilder() |
| .setAudioGains(new AudioGain[] {new GainBuilder().build()}) |
| .setAddressName(MEDIA_TEST_DEVICE) |
| .build(); |
| return new AudioDeviceInfo[] { |
| mMediaOutputDevice, |
| new AudioDeviceInfoBuilder() |
| .setAudioGains(new AudioGain[] {new GainBuilder().build()}) |
| .setAddressName(NAVIGATION_TEST_DEVICE) |
| .build(), |
| new AudioDeviceInfoBuilder() |
| .setAudioGains(new AudioGain[] {new GainBuilder().build()}) |
| .setAddressName(CALL_TEST_DEVICE) |
| .build(), |
| new AudioDeviceInfoBuilder() |
| .setAudioGains(new AudioGain[] {new GainBuilder().build()}) |
| .setAddressName(SYSTEM_BUS_DEVICE) |
| .build(), |
| new AudioDeviceInfoBuilder() |
| .setAudioGains(new AudioGain[] {new GainBuilder().build()}) |
| .setAddressName(NOTIFICATION_TEST_DEVICE) |
| .build(), |
| new AudioDeviceInfoBuilder() |
| .setAudioGains(new AudioGain[] {new GainBuilder().build()}) |
| .setAddressName(VOICE_TEST_DEVICE) |
| .build(), |
| new AudioDeviceInfoBuilder() |
| .setAudioGains(new AudioGain[] {new GainBuilder().build()}) |
| .setAddressName(RING_TEST_DEVICE) |
| .build(), |
| new AudioDeviceInfoBuilder() |
| .setAudioGains(new AudioGain[] {new GainBuilder().build()}) |
| .setAddressName(ALARM_TEST_DEVICE) |
| .build(), |
| new AudioDeviceInfoBuilder() |
| .setAudioGains(new AudioGain[] {new GainBuilder().build()}) |
| .setAddressName(SECONDARY_TEST_DEVICE_1) |
| .build(), |
| new AudioDeviceInfoBuilder() |
| .setAudioGains(new AudioGain[] {new GainBuilder().build()}) |
| .setAddressName(SECONDARY_TEST_DEVICE_2) |
| .build(), |
| new AudioDeviceInfoBuilder() |
| .setAudioGains(new AudioGain[] {new GainBuilder().build()}) |
| .setAddressName(TERTIARY_TEST_DEVICE_1) |
| .build(), |
| new AudioDeviceInfoBuilder() |
| .setAudioGains(new AudioGain[] {new GainBuilder().build()}) |
| .setAddressName(TERTIARY_TEST_DEVICE_2) |
| .build(), |
| new AudioDeviceInfoBuilder() |
| .setAudioGains(new AudioGain[] {new GainBuilder().build()}) |
| .setAddressName(QUATERNARY_TEST_DEVICE_1) |
| .build(), |
| new AudioDeviceInfoBuilder() |
| .setAudioGains(new AudioGain[] {new GainBuilder().build()}) |
| .setAddressName(OEM_TEST_DEVICE) |
| .build(), |
| new AudioDeviceInfoBuilder() |
| .setAudioGains(new AudioGain[] {new GainBuilder().build()}) |
| .setAddressName(MIRROR_TEST_DEVICE).build(), |
| }; |
| } |
| |
| private void mockCoreAudioRoutingAndVolume() { |
| doReturn(CoreAudioRoutingUtils.getProductStrategies()) |
| .when(() -> AudioManager.getAudioProductStrategies()); |
| doReturn(CoreAudioRoutingUtils.getVolumeGroups()) |
| .when(() -> AudioManager.getAudioVolumeGroups()); |
| |
| when(mAudioManager.getVolumeGroupIdForAttributes(CoreAudioRoutingUtils.MUSIC_ATTRIBUTES)) |
| .thenReturn(CoreAudioRoutingUtils.MUSIC_GROUP_ID); |
| when(mAudioManager.getMinVolumeIndexForAttributes( |
| eq(CoreAudioRoutingUtils.MUSIC_ATTRIBUTES))) |
| .thenReturn(CoreAudioRoutingUtils.MUSIC_MIN_INDEX); |
| when(mAudioManager.getMaxVolumeIndexForAttributes( |
| eq(CoreAudioRoutingUtils.MUSIC_ATTRIBUTES))) |
| .thenReturn(CoreAudioRoutingUtils.MUSIC_MAX_INDEX); |
| when(mAudioManager.getVolumeIndexForAttributes(eq(CoreAudioRoutingUtils.MUSIC_ATTRIBUTES))) |
| .thenReturn(CoreAudioRoutingUtils.MUSIC_AM_INIT_INDEX); |
| when(mAudioManager.getLastAudibleVolumeForVolumeGroup(CoreAudioRoutingUtils.MUSIC_GROUP_ID)) |
| .thenReturn(CoreAudioRoutingUtils.MUSIC_AM_INIT_INDEX); |
| when(mAudioManager.isVolumeGroupMuted(CoreAudioRoutingUtils.MUSIC_GROUP_ID)) |
| .thenReturn(false); |
| |
| when(mAudioManager.getVolumeGroupIdForAttributes(CoreAudioRoutingUtils.NAV_ATTRIBUTES)) |
| .thenReturn(CoreAudioRoutingUtils.NAV_GROUP_ID); |
| when(mAudioManager.getMinVolumeIndexForAttributes(eq(CoreAudioRoutingUtils.NAV_ATTRIBUTES))) |
| .thenReturn(CoreAudioRoutingUtils.NAV_MIN_INDEX); |
| when(mAudioManager.getMaxVolumeIndexForAttributes(eq(CoreAudioRoutingUtils.NAV_ATTRIBUTES))) |
| .thenReturn(CoreAudioRoutingUtils.NAV_MAX_INDEX); |
| when(mAudioManager.isVolumeGroupMuted(CoreAudioRoutingUtils.NAV_GROUP_ID)) |
| .thenReturn(false); |
| |
| when(mAudioManager.getVolumeGroupIdForAttributes(CoreAudioRoutingUtils.OEM_ATTRIBUTES)) |
| .thenReturn(CoreAudioRoutingUtils.OEM_GROUP_ID); |
| when(mAudioManager.getMinVolumeIndexForAttributes(eq(CoreAudioRoutingUtils.OEM_ATTRIBUTES))) |
| .thenReturn(CoreAudioRoutingUtils.OEM_MIN_INDEX); |
| when(mAudioManager.getMaxVolumeIndexForAttributes(eq(CoreAudioRoutingUtils.OEM_ATTRIBUTES))) |
| .thenReturn(CoreAudioRoutingUtils.OEM_MAX_INDEX); |
| when(mAudioManager.isVolumeGroupMuted(CoreAudioRoutingUtils.OEM_GROUP_ID)) |
| .thenReturn(false); |
| } |
| |
| private static AudioFocusInfo createAudioFocusInfoForMedia() { |
| return createAudioFocusInfoForMedia(MEDIA_APP_UID); |
| } |
| |
| private static AudioFocusInfo createAudioFocusInfoForMedia(int uid) { |
| AudioAttributes.Builder builder = new AudioAttributes.Builder(); |
| builder.setUsage(USAGE_MEDIA); |
| |
| return new AudioFocusInfo(builder.build(), uid, MEDIA_CLIENT_ID, |
| MEDIA_PACKAGE_NAME, AUDIOFOCUS_GAIN, AUDIOFOCUS_LOSS, MEDIA_EMPTY_FLAG, SDK_INT); |
| } |
| |
| private List<Integer> getFocusChanges(AudioFocusInfo info) { |
| ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(Integer.class); |
| verify(mAudioManager, atLeastOnce()).dispatchAudioFocusChange(eq(info), captor.capture(), |
| any()); |
| return captor.getAllValues(); |
| } |
| |
| private void verifyMediaDuckingInfoInZone(ArgumentCaptor<List<CarDuckingInfo>> |
| carDuckingInfosCaptor, int zoneId, String message) { |
| expectWithMessage("Zone size of notified ducking info " + message) |
| .that(carDuckingInfosCaptor.getValue().size()).isEqualTo(1); |
| CarDuckingInfo duckingInfo = carDuckingInfosCaptor.getValue().get(0); |
| expectWithMessage("Ducking info zone id " + message) |
| .that(duckingInfo.mZoneId).isEqualTo(zoneId); |
| expectWithMessage("Audio attributes holding focus " + message) |
| .that(CarHalAudioUtils.metadataToAudioAttributes(duckingInfo |
| .mPlaybackMetaDataHoldingFocus)) |
| .containsExactly(CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA)); |
| } |
| |
| private CarAudioZoneConfigInfo getZoneConfigToSwitch(int zoneId) { |
| CarAudioZoneConfigInfo currentZoneConfigInfo = |
| mCarAudioService.getCurrentAudioZoneConfigInfo(zoneId); |
| List<CarAudioZoneConfigInfo> zoneConfigInfos = |
| mCarAudioService.getAudioZoneConfigInfos(zoneId); |
| |
| for (int index = 0; index < zoneConfigInfos.size(); index++) { |
| if (!currentZoneConfigInfo.equals(zoneConfigInfos.get(index))) { |
| return zoneConfigInfos.get(index); |
| } |
| } |
| return null; |
| } |
| |
| private static final class TestPrimaryZoneMediaAudioRequestCallback extends |
| IPrimaryZoneMediaAudioRequestCallback.Stub { |
| private long mRequestId = INVALID_REQUEST_ID; |
| private CarOccupantZoneManager.OccupantZoneInfo mInfo; |
| private CountDownLatch mStatusLatch = new CountDownLatch(1); |
| private int mStatus; |
| |
| @Override |
| public void onRequestMediaOnPrimaryZone(CarOccupantZoneManager.OccupantZoneInfo info, |
| long requestId) { |
| mInfo = info; |
| mRequestId = requestId; |
| mStatusLatch.countDown(); |
| } |
| |
| @Override |
| public void onMediaAudioRequestStatusChanged( |
| @NonNull CarOccupantZoneManager.OccupantZoneInfo info, |
| long requestId, int status) { |
| mInfo = info; |
| mRequestId = requestId; |
| mStatus = status; |
| mStatusLatch.countDown(); |
| } |
| |
| private void waitForCallback() throws Exception { |
| mStatusLatch.await(TEST_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS); |
| } |
| |
| public void reset() { |
| mInfo = null; |
| mRequestId = INVALID_REQUEST_ID; |
| mStatus = INVALID_STATUS; |
| mStatusLatch = new CountDownLatch(1); |
| } |
| } |
| |
| private static final class TestMediaRequestStatusCallback extends |
| IMediaAudioRequestStatusCallback.Stub { |
| private long mRequestId = INVALID_REQUEST_ID; |
| private CarOccupantZoneManager.OccupantZoneInfo mInfo; |
| private int mStatus; |
| private final CountDownLatch mStatusLatch = new CountDownLatch(1); |
| |
| @Override |
| public void onMediaAudioRequestStatusChanged( |
| @NonNull CarOccupantZoneManager.OccupantZoneInfo info, |
| long requestId, @CarAudioManager.MediaAudioRequestStatus int status) |
| throws RemoteException { |
| mInfo = info; |
| mRequestId = requestId; |
| mStatus = status; |
| mStatusLatch.countDown(); |
| } |
| |
| private void waitForCallback() throws Exception { |
| mStatusLatch.await(TEST_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS); |
| } |
| } |
| |
| private static final class TestAudioZonesMirrorStatusCallbackCallback extends |
| IAudioZonesMirrorStatusCallback.Stub { |
| |
| private static final long TEST_CALLBACK_TIMEOUT_MS = 300; |
| |
| private List<int[]> mZoneIds = new ArrayList<>(); |
| private List<Integer> mStatus = new ArrayList<>(); |
| private int mNumberOfCalls = 0; |
| private CountDownLatch mStatusLatch; |
| |
| private TestAudioZonesMirrorStatusCallbackCallback(int count) { |
| mStatusLatch = new CountDownLatch(count); |
| } |
| |
| @Override |
| public void onAudioZonesMirrorStatusChanged(int[] zoneIds, int status) { |
| mZoneIds.add(zoneIds); |
| mStatus.add(status); |
| mNumberOfCalls++; |
| mStatusLatch.countDown(); |
| } |
| |
| private void waitForCallback() throws Exception { |
| mStatusLatch.await(TEST_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS); |
| } |
| |
| public void reset(int count) { |
| mStatusLatch = new CountDownLatch(count); |
| } |
| |
| private int[] getLastZoneIds() { |
| return mZoneIds.get(mZoneIds.size() - 1); |
| } |
| |
| private int[] getZoneIds(int index) { |
| return mZoneIds.get(index); |
| } |
| |
| public int getLastStatus() { |
| return mStatus.get(mStatus.size() - 1); |
| } |
| |
| public int getStatus(int index) { |
| return mStatus.get(index); |
| } |
| } |
| |
| private static final class SwitchAudioZoneConfigCallbackImpl extends |
| ISwitchAudioZoneConfigCallback.Stub { |
| private CountDownLatch mStatusLatch = new CountDownLatch(1); |
| private CarAudioZoneConfigInfo mZoneConfig; |
| private boolean mIsSuccessful; |
| |
| @Override |
| public void onAudioZoneConfigSwitched(CarAudioZoneConfigInfo zoneConfig, |
| boolean isSuccessful) throws RemoteException { |
| mZoneConfig = zoneConfig; |
| mIsSuccessful = isSuccessful; |
| mStatusLatch.countDown(); |
| } |
| |
| private void waitForCallback() throws Exception { |
| mStatusLatch.await(TEST_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS); |
| } |
| |
| CarAudioZoneConfigInfo getZoneConfig() { |
| return mZoneConfig; |
| } |
| |
| boolean getSwitchStatus() { |
| return mIsSuccessful; |
| } |
| } |
| } |