blob: cb937e21202e723cca45ecc5cae309ea0dbee5cf [file] [log] [blame]
/*
* 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.PlatformVersion.VERSION_CODES.UPSIDE_DOWN_CAKE_0;
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.AUDIO_MIRROR_CAN_ENABLE;
import static android.car.media.CarAudioManager.AUDIO_MIRROR_OUT_OF_OUTPUT_DEVICES;
import static android.car.media.CarAudioManager.CONFIG_STATUS_AUTO_SWITCHED;
import static android.car.media.CarAudioManager.CONFIG_STATUS_CHANGED;
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.mockCarGetPlatformVersion;
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_BLUETOOTH_A2DP;
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.ERROR;
import static android.media.AudioManager.EXTRA_VOLUME_STREAM_TYPE;
import static android.media.AudioManager.FLAG_FROM_KEY;
import static android.media.AudioManager.FLAG_PLAY_SOUND;
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.CarHalAudioUtils.usageToMetadata;
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.feature.Flags;
import android.car.media.CarAudioManager;
import android.car.media.CarAudioPatchHandle;
import android.car.media.CarAudioZoneConfigInfo;
import android.car.media.CarVolumeGroupEvent;
import android.car.media.CarVolumeGroupInfo;
import android.car.media.IAudioZoneConfigurationsChangeCallback;
import android.car.media.IAudioZonesMirrorStatusCallback;
import android.car.media.ICarVolumeEventCallback;
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.AudioDeviceCallback;
import android.media.AudioDeviceInfo;
import android.media.AudioFocusInfo;
import android.media.AudioGain;
import android.media.AudioManager;
import android.media.AudioManager.AudioPlaybackCallback;
import android.media.AudioManager.AudioServerStateCallback;
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.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.util.NoSuchPropertyException;
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.Rule;
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.Arrays;
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 long TEST_ZONE_CONFIG_CALLBACK_TIMEOUT_MS = 350;
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_CONFIG_0 = "secondary_zone_bus_100";
private static final String SECONDARY_TEST_DEVICE_CONFIG_1_0 = "secondary_zone_bus_200";
private static final String SECONDARY_TEST_DEVICE_CONFIG_1_1 = "secondary_zone_bus_201";
private static final String TERTIARY_TEST_DEVICE_1 = "tertiary_zone_bus_100";
private static final String TERTIARY_TEST_DEVICE_2 = "tertiary_zone_bus_200";
private static final String QUATERNARY_TEST_DEVICE_1 = "quaternary_zone_bus_1";
private static final String TEST_REAR_ROW_3_DEVICE = "rear_row_three_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";
private static final String DEFAULT_CONFIG_NAME_DYNAMIC_DEVICES = "primary zone config 0";
private static final String SECONDARY_CONFIG_NAME_DYNAMIC_DEVICES = "primary zone BT media";
private static final String TERTIARY_CONFIG_NAME_DYNAMIC_DEVICES =
"primary zone headphones media";
private static final String MIRROR_OFF_SIGNAL = "mirroring=off";
// 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;
private static final int TEST_REAR_ROW_3_ZONE_ID = 4;
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_REAR_ROW_3_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_ZONE_GROUP_0 = 0;
private static final int TEST_PRIMARY_ZONE_GROUP_1 = 1;
private static final int TEST_PRIMARY_ZONE_GROUP_2 = 2;
private static final int TEST_SECONDARY_ZONE_GROUP_0 = 0;
private static final int TEST_SECONDARY_ZONE_GROUP_1 = 1;
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_REAR_ROW_3_OCCUPANT_ZONE_ID = 5;
private static final int TEST_UNASSIGNED_OCCUPANT_ZONE_ID = 6;
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 CarOccupantZoneManager.OccupantZoneInfo
TEST_REAR_ROW_3_PASSENGER_OCCUPANT =
getOccupantInfo(TEST_REAR_ROW_3_OCCUPANT_ZONE_ID,
CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER,
VehicleAreaSeat.SEAT_ROW_3_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_PASSENGER_USER_ID = 13;
private static final int TEST_REAR_ROW_3_PASSENGER_USER_ID = 14;
private static final int TEST_GAIN_INDEX = 4;
// TODO(b/273800524): create a utility test class for audio attributes.
private static final AudioAttributes ATTRIBUTES_UNKNOWN =
CarAudioContext.getAudioAttributeFromUsage(USAGE_UNKNOWN);
private static final AudioAttributes ATTRIBUTES_GAME =
CarAudioContext.getAudioAttributeFromUsage(USAGE_GAME);
private static final AudioAttributes ATTRIBUTES_MEDIA =
CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA);
private static final AudioAttributes ATTRIBUTES_NOTIFICATION =
CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION);
private static final AudioAttributes ATTRIBUTES_NOTIFICATION_EVENT =
CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION_EVENT);
private static final AudioAttributes ATTRIBUTES_ANNOUNCEMENT =
CarAudioContext.getAudioAttributeFromUsage(USAGE_ANNOUNCEMENT);
private static final AudioAttributes ATTRIBUTES_ASSISTANCE_NAVIGATION_GUIDANCE =
CarAudioContext.getAudioAttributeFromUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE);
private static final AudioAttributes ATTRIBUTES_ASSISTANCE_ACCESSIBILITY =
CarAudioContext.getAudioAttributeFromUsage(USAGE_ASSISTANCE_ACCESSIBILITY);
private static final AudioAttributes ATTRIBUTES_ASSISTANT =
CarAudioContext.getAudioAttributeFromUsage(USAGE_ASSISTANT);
private static final AudioAttributes ATTRIBUTES_NOTIFICATION_RINGTONE =
CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION_RINGTONE);
private static final AudioAttributes ATTRIBUTES_VOICE_COMMUNICATION =
CarAudioContext.getAudioAttributeFromUsage(USAGE_VOICE_COMMUNICATION);
private static final AudioAttributes ATTRIBUTES_CALL_ASSISTANT =
CarAudioContext.getAudioAttributeFromUsage(USAGE_CALL_ASSISTANT);
private static final AudioAttributes ATTRIBUTES_VOICE_COMMUNICATION_SIGNALLING =
CarAudioContext.getAudioAttributeFromUsage(USAGE_VOICE_COMMUNICATION_SIGNALLING);
private static final AudioAttributes ATTRIBUTES_ALARM =
CarAudioContext.getAudioAttributeFromUsage(USAGE_ALARM);
private static final AudioAttributes ATTRIBUTES_ASSISTANCE_SONIFICATION =
CarAudioContext.getAudioAttributeFromUsage(USAGE_ASSISTANCE_SONIFICATION);
private static final AudioAttributes ATTRIBUTES_EMERGENCY =
CarAudioContext.getAudioAttributeFromUsage(USAGE_EMERGENCY);
private static final AudioAttributes ATTRIBUTES_SAFETY =
CarAudioContext.getAudioAttributeFromUsage(USAGE_SAFETY);
private static final AudioAttributes ATTRIBUTES_VEHICLE_STATUS =
CarAudioContext.getAudioAttributeFromUsage(USAGE_VEHICLE_STATUS);
private static final List<AudioAttributes> TEST_PRIMARY_ZONE_AUDIO_ATTRIBUTES_0 = List.of(
ATTRIBUTES_UNKNOWN, ATTRIBUTES_GAME, ATTRIBUTES_MEDIA, ATTRIBUTES_NOTIFICATION,
ATTRIBUTES_NOTIFICATION_EVENT, ATTRIBUTES_ANNOUNCEMENT);
private static final List<AudioAttributes> TEST_PRIMARY_ZONE_AUDIO_ATTRIBUTES_1 = List.of(
ATTRIBUTES_ASSISTANCE_NAVIGATION_GUIDANCE, ATTRIBUTES_ASSISTANCE_ACCESSIBILITY,
ATTRIBUTES_ASSISTANT);
private static final List<AudioAttributes> TEST_SECONDARY_ZONE_AUDIO_ATTRIBUTES_DEFAULT =
List.of(ATTRIBUTES_UNKNOWN, ATTRIBUTES_GAME, ATTRIBUTES_MEDIA,
ATTRIBUTES_ASSISTANCE_NAVIGATION_GUIDANCE, ATTRIBUTES_ASSISTANCE_ACCESSIBILITY,
ATTRIBUTES_ASSISTANT, ATTRIBUTES_NOTIFICATION_RINGTONE,
ATTRIBUTES_VOICE_COMMUNICATION, ATTRIBUTES_CALL_ASSISTANT,
ATTRIBUTES_VOICE_COMMUNICATION_SIGNALLING, ATTRIBUTES_ALARM,
ATTRIBUTES_NOTIFICATION, ATTRIBUTES_NOTIFICATION_EVENT,
ATTRIBUTES_ASSISTANCE_SONIFICATION, ATTRIBUTES_EMERGENCY, ATTRIBUTES_SAFETY,
ATTRIBUTES_VEHICLE_STATUS, ATTRIBUTES_ANNOUNCEMENT);
private static final List<AudioAttributes> TEST_SECONDARY_ZONE_AUDIO_ATTRIBUTES_0 = List.of(
ATTRIBUTES_UNKNOWN, ATTRIBUTES_GAME, ATTRIBUTES_MEDIA,
ATTRIBUTES_ASSISTANCE_NAVIGATION_GUIDANCE, ATTRIBUTES_ASSISTANCE_ACCESSIBILITY,
ATTRIBUTES_ASSISTANT, ATTRIBUTES_NOTIFICATION, ATTRIBUTES_NOTIFICATION_EVENT,
ATTRIBUTES_ANNOUNCEMENT);
private static final List<AudioAttributes> TEST_SECONDARY_ZONE_AUDIO_ATTRIBUTES_1 = List.of(
ATTRIBUTES_NOTIFICATION_RINGTONE, ATTRIBUTES_VOICE_COMMUNICATION,
ATTRIBUTES_CALL_ASSISTANT, ATTRIBUTES_VOICE_COMMUNICATION_SIGNALLING, ATTRIBUTES_ALARM,
ATTRIBUTES_ASSISTANCE_SONIFICATION, ATTRIBUTES_EMERGENCY, ATTRIBUTES_SAFETY,
ATTRIBUTES_VEHICLE_STATUS);
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);
@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 mTempCarAudioConfigFile;
private Context mContext;
private AudioDeviceInfo mMicrophoneInputDevice;
private AudioDeviceInfo mFmTunerInputDevice;
private AudioDeviceInfo mMediaOutputDevice;
private AudioDeviceInfo mNotificationOutpuBus;
private AudioDeviceInfo mNavOutputDevice;
private AudioDeviceInfo mVoiceOutpuBus;
private AudioDeviceInfo mSecondaryConfig0Group0Device;
private AudioDeviceInfo mSecondaryConfig1Group0Device;
private AudioDeviceInfo mSecondaryConfig1Group1Device;
private AudioDeviceInfo mBTAudioDeviceInfo;
private CarVolumeGroupInfo mTestPrimaryZoneVolumeInfo0;
private CarVolumeGroupInfo mTestPrimaryZoneUmMutedVolueInfo0;
private CarVolumeGroupInfo mTestPrimaryZoneVolumeInfo1;
private CarVolumeGroupInfo mTestSecondaryConfig0VolumeGroup0Info;
private CarVolumeGroupInfo mTestSecondaryZoneConfig1VolumeInfo0;
private CarVolumeGroupInfo mTestSecondaryZoneConfig1VolumeInfo1;
private CarVolumeGroupEvent mTestCarVolumeGroupEvent;
private CarVolumeGroupEvent mTestCarMuteGroupEvent;
private CarVolumeGroupEvent mTestCarZoneReconfigurationEvent;
@Captor
private ArgumentCaptor<BroadcastReceiver> mVolumeReceiverCaptor;
private int mRegistrationCount = 0;
private List<Integer> mAudioPolicyRegistrationStatus = new ArrayList<>();
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
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(CoreAudioHelper.class)
.spyStatic(AudioControlFactory.class)
.spyStatic(SystemProperties.class)
.spyStatic(ServiceManager.class)
.spyStatic(Car.class);
}
@Before
public void setUp() throws Exception {
mContext = ApplicationProvider.getApplicationContext();
mockCarGetPlatformVersion(UPSIDE_DOWN_CAKE_0);
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 {
if (mTempCarAudioConfigFile != null) {
mTempCarAudioConfigFile.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_PASSENGER_USER_ID);
when(mMockOccupantZoneService.getUserForOccupant(TEST_REAR_ROW_3_OCCUPANT_ZONE_ID))
.thenReturn(TEST_REAR_ROW_3_PASSENGER_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_PASSENGER_USER_ID);
when(mMockOccupantZoneService.getAudioZoneIdForOccupant(TEST_REAR_ROW_3_ZONE_ID))
.thenReturn(TEST_REAR_ROW_3_PASSENGER_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_PASSENGER_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_ROW_3_ZONE_ID))
.thenReturn(TEST_REAR_ROW_3_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);
when(mMockOccupantZoneService.getOccupantForAudioZoneId(TEST_REAR_LEFT_ZONE_ID))
.thenReturn(TEST_REAR_LEFT_PASSENGER_OCCUPANT);
when(mMockOccupantZoneService.getOccupantForAudioZoneId(TEST_REAR_ROW_3_ZONE_ID))
.thenReturn(TEST_REAR_ROW_3_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();
}
private void setUpAudioManager() throws Exception {
AudioDeviceInfo[] outputDevices = generateOutputDeviceInfos();
AudioDeviceInfo[] inputDevices = generateInputDeviceInfos();
mTestPrimaryZoneVolumeInfo0 =
new CarVolumeGroupInfo.Builder("config 0 group " + TEST_PRIMARY_ZONE_GROUP_0,
PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0).setMuted(true)
.setMinVolumeGainIndex(0).setMaxVolumeGainIndex(MAX_GAIN / STEP_SIZE)
.setVolumeGainIndex(DEFAULT_GAIN / STEP_SIZE)
.setAudioAttributes(TEST_PRIMARY_ZONE_AUDIO_ATTRIBUTES_0)
.setAudioDeviceAttributes(List.of(
new AudioDeviceAttributes(mNotificationOutpuBus),
new AudioDeviceAttributes(mMediaOutputDevice))).build();
mTestPrimaryZoneUmMutedVolueInfo0 =
new CarVolumeGroupInfo.Builder("config 0 group " + TEST_PRIMARY_ZONE_GROUP_0,
PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0).setMuted(false)
.setMinVolumeGainIndex(0).setMaxVolumeGainIndex(MAX_GAIN / STEP_SIZE)
.setVolumeGainIndex(DEFAULT_GAIN / STEP_SIZE)
.setAudioAttributes(TEST_PRIMARY_ZONE_AUDIO_ATTRIBUTES_0)
.setAudioDeviceAttributes(List.of(
new AudioDeviceAttributes(mNotificationOutpuBus),
new AudioDeviceAttributes(mMediaOutputDevice))).build();
mTestPrimaryZoneVolumeInfo1 =
new CarVolumeGroupInfo.Builder("config 0 group " + TEST_PRIMARY_ZONE_GROUP_1,
PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_1).setMuted(true)
.setMinVolumeGainIndex(0).setMaxVolumeGainIndex(MAX_GAIN / STEP_SIZE)
.setAudioAttributes(TEST_PRIMARY_ZONE_AUDIO_ATTRIBUTES_1)
.setVolumeGainIndex(DEFAULT_GAIN / STEP_SIZE)
.setAudioDeviceAttributes(List.of(
new AudioDeviceAttributes(mVoiceOutpuBus),
new AudioDeviceAttributes(mNavOutputDevice))).build();
mTestSecondaryConfig0VolumeGroup0Info =
new CarVolumeGroupInfo.Builder("config 0 group " + TEST_SECONDARY_ZONE_GROUP_0,
TEST_REAR_LEFT_ZONE_ID, TEST_SECONDARY_ZONE_GROUP_0)
.setMinVolumeGainIndex(0).setMaxVolumeGainIndex(MAX_GAIN / STEP_SIZE)
.setAudioAttributes(TEST_SECONDARY_ZONE_AUDIO_ATTRIBUTES_DEFAULT)
.setVolumeGainIndex(DEFAULT_GAIN / STEP_SIZE)
.setAudioDeviceAttributes(List.of(
new AudioDeviceAttributes(mSecondaryConfig0Group0Device)))
.build();
mTestSecondaryZoneConfig1VolumeInfo0 =
new CarVolumeGroupInfo.Builder("config 1 group " + TEST_SECONDARY_ZONE_GROUP_0,
TEST_REAR_LEFT_ZONE_ID, TEST_SECONDARY_ZONE_GROUP_0)
.setMinVolumeGainIndex(0).setMaxVolumeGainIndex(MAX_GAIN / STEP_SIZE)
.setAudioAttributes(TEST_SECONDARY_ZONE_AUDIO_ATTRIBUTES_0)
.setVolumeGainIndex(DEFAULT_GAIN / STEP_SIZE)
.setAudioDeviceAttributes(List.of(new AudioDeviceAttributes(
mSecondaryConfig1Group0Device))).build();
mTestSecondaryZoneConfig1VolumeInfo1 =
new CarVolumeGroupInfo.Builder("config 1 group " + TEST_SECONDARY_ZONE_GROUP_1,
TEST_REAR_LEFT_ZONE_ID, TEST_SECONDARY_ZONE_GROUP_1)
.setMinVolumeGainIndex(0).setMaxVolumeGainIndex(MAX_GAIN / STEP_SIZE)
.setAudioAttributes(TEST_SECONDARY_ZONE_AUDIO_ATTRIBUTES_1)
.setVolumeGainIndex(DEFAULT_GAIN / STEP_SIZE)
.setAudioDeviceAttributes(List.of(new AudioDeviceAttributes(
mSecondaryConfig1Group1Device))).build();
mTestCarVolumeGroupEvent =
new CarVolumeGroupEvent.Builder(List.of(mTestPrimaryZoneUmMutedVolueInfo0),
CarVolumeGroupEvent.EVENT_TYPE_VOLUME_GAIN_INDEX_CHANGED,
List.of(CarVolumeGroupEvent.EXTRA_INFO_VOLUME_INDEX_CHANGED_BY_UI)).build();
mTestCarMuteGroupEvent =
new CarVolumeGroupEvent.Builder(List.of(mTestPrimaryZoneUmMutedVolueInfo0),
CarVolumeGroupEvent.EVENT_TYPE_MUTE_CHANGED,
List.of(CarVolumeGroupEvent.EXTRA_INFO_VOLUME_INDEX_CHANGED_BY_UI)).build();
mTestCarZoneReconfigurationEvent =
new CarVolumeGroupEvent.Builder(List.of(mTestPrimaryZoneUmMutedVolueInfo0),
CarVolumeGroupEvent.EVENT_TYPE_ZONE_CONFIGURATION_CHANGED,
List.of(CarVolumeGroupEvent.EXTRA_INFO_VOLUME_INDEX_CHANGED_BY_UI)).build();
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);
// Only return an specific result if testing failures at different phases.
return mAudioPolicyRegistrationStatus.isEmpty()
? SUCCESS : mAudioPolicyRegistrationStatus.get(mRegistrationCount++);
});
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_ONE);
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 init_withVolumeControlPolicyRegistrationError_fails() throws Exception {
mAudioPolicyRegistrationStatus.add(ERROR);
CarAudioService service = setUpAudioServiceWithoutInit();
IllegalStateException thrown =
assertThrows(IllegalStateException.class, () -> service.init());
expectWithMessage("Audio control policy registration exception").that(thrown)
.hasMessageThat().containsMatch("car audio service's volume control audio policy");
}
@Test
public void init_withRepeatedDynamicDevicesInConfig_fails() throws Exception {
setUpTempFileForAudioConfiguration(
R.raw.car_audio_configuration_repeated_dynamic_devices_in_config);
CarAudioService service = setUpAudioServiceWithDynamicDevices(mTempCarAudioConfigFile);
RuntimeException thrown =
assertThrows(RuntimeException.class, () -> service.init());
expectWithMessage("Car audio zone config with multiple dynamic devices exception")
.that(thrown).hasMessageThat()
.containsMatch("Invalid zone configurations for zone");
}
@Test
public void init_withFocusControlPolicyRegistrationError_fails() throws Exception {
mAudioPolicyRegistrationStatus.add(SUCCESS);
mAudioPolicyRegistrationStatus.add(ERROR);
CarAudioService service = setUpAudioServiceWithoutInit();
IllegalStateException thrown =
assertThrows(IllegalStateException.class, () -> service.init());
expectWithMessage("Audio control policy registration exception").that(thrown)
.hasMessageThat().containsMatch("car audio service's focus control audio policy");
}
@Test
public void init_withAudioRoutingPolicyRegistrationError_fails() throws Exception {
mAudioPolicyRegistrationStatus.add(SUCCESS);
mAudioPolicyRegistrationStatus.add(SUCCESS);
mAudioPolicyRegistrationStatus.add(ERROR);
CarAudioService service = setUpAudioServiceWithoutInit();
IllegalStateException thrown =
assertThrows(IllegalStateException.class, () -> service.init());
expectWithMessage("Audio routing policy registration exception").that(thrown)
.hasMessageThat().containsMatch("Audio routing policy registration");
}
@Test
public void init_initializesAudioServiceCallbacks() throws Exception {
CarAudioService service = setUpAudioServiceWithoutInit();
service.init();
verify(mAudioManager).setAudioServerStateCallback(any(), any());
verify(mAudioManager, never()).registerAudioDeviceCallback(any(), any());
}
@Test
public void init_initializesAudioServiceCallbacks_withDynamicDevices() throws Exception {
CarAudioService service = setUpAudioServiceWithDynamicDevices();
service.init();
verify(mAudioManager).setAudioServerStateCallback(any(), any());
verify(mAudioManager).registerAudioDeviceCallback(any(), any());
}
@Test
public void init_withDynamicDevices() throws Exception {
CarAudioService audioServiceWithDynamicDevices = setUpAudioServiceWithDynamicDevices();
audioServiceWithDynamicDevices.init();
List<CarAudioZoneConfigInfo> zoneConfigInfos =
audioServiceWithDynamicDevices.getAudioZoneConfigInfos(PRIMARY_AUDIO_ZONE);
List<String> names = zoneConfigInfos.stream().map(config -> config.getName()).toList();
expectWithMessage("Dynamic configuration names").that(names).containsExactly(
DEFAULT_CONFIG_NAME_DYNAMIC_DEVICES, SECONDARY_CONFIG_NAME_DYNAMIC_DEVICES,
TERTIARY_CONFIG_NAME_DYNAMIC_DEVICES);
CarAudioZoneConfigInfo btConfig = zoneConfigInfos.stream()
.filter(config -> config.getName().equals(SECONDARY_CONFIG_NAME_DYNAMIC_DEVICES))
.findFirst().orElseThrow();
expectWithMessage("Bluetooth configuration by default active status")
.that(btConfig.isActive()).isFalse();
}
@Test
public void release_releasesAudioServiceCallbacks() throws Exception {
CarAudioService service = setUpAudioService();
service.release();
verify(mAudioManager, never()).unregisterAudioDeviceCallback(any());
verify(mAudioManager).clearAudioServerStateCallback();
}
@Test
public void release_releasesAudioServiceCallbacks_withDynamicDevices() throws Exception {
CarAudioService service = setUpAudioServiceWithDynamicDevices();
service.init();
service.release();
verify(mAudioManager).unregisterAudioDeviceCallback(any());
verify(mAudioManager).clearAudioServerStateCallback();
}
@Test
public void getAudioZoneIds_withBaseConfiguration_returnAllTheZones() throws Exception {
CarAudioService service = setUpAudioService();
expectWithMessage("Car Audio Service Zones")
.that(service.getAudioZoneIds()).asList()
.containsExactly(PRIMARY_AUDIO_ZONE, TEST_REAR_LEFT_ZONE_ID,
TEST_REAR_RIGHT_ZONE_ID, TEST_FRONT_ZONE_ID, TEST_REAR_ROW_3_ZONE_ID);
}
@Test
public void getVolumeGroupCount_onPrimaryZone_returnsAllGroups() throws Exception {
CarAudioService service = setUpAudioService();
expectWithMessage("Primary zone car volume group count")
.that(service.getVolumeGroupCount(PRIMARY_AUDIO_ZONE))
.isEqualTo(PRIMARY_ZONE_VOLUME_GROUP_COUNT);
}
@Test
public void getVolumeGroupCount_onPrimaryZone_withNonDynamicRouting_returnsAllGroups()
throws Exception {
CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
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() throws Exception {
CarAudioService service = setUpAudioService();
expectWithMessage("Primary zone's media car volume group id")
.that(service.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE, USAGE_MEDIA))
.isEqualTo(MEDIA_VOLUME_GROUP_ID);
}
@Test
public void getVolumeGroupIdForUsage_withNonDynamicRouting_forMusicUsage() throws Exception {
CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
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() throws Exception {
CarAudioService service = setUpAudioService();
expectWithMessage("Primary zone's navigation car volume group id")
.that(service.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE,
USAGE_ASSISTANCE_NAVIGATION_GUIDANCE))
.isEqualTo(NAVIGATION_VOLUME_GROUP_ID);
}
@Test
public void getVolumeGroupIdForUsage_withNonDynamicRouting_forNavigationUsage()
throws Exception {
CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
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() throws Exception {
CarAudioService service = setUpAudioService();
expectWithMessage("Primary zone's invalid car volume group id")
.that(service.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE, INVALID_USAGE))
.isEqualTo(INVALID_VOLUME_GROUP_ID);
}
@Test
public void
getVolumeGroupIdForUsage_forInvalidUsage_withNonDynamicRouting_returnsInvalidGroupId()
throws Exception {
CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
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() throws Exception {
CarAudioService service = setUpAudioService();
expectWithMessage("Primary zone's unknown car volume group id")
.that(service.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE, USAGE_UNKNOWN))
.isEqualTo(MEDIA_VOLUME_GROUP_ID);
}
@Test
public void getVolumeGroupIdForUsage_forVirtualUsage_returnsInvalidGroupId() throws Exception {
CarAudioService service = setUpAudioService();
expectWithMessage("Primary zone's virtual car volume group id")
.that(service.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE,
AudioManagerHelper.getUsageVirtualSource()))
.isEqualTo(INVALID_VOLUME_GROUP_ID);
}
@Test
public void getVolumeGroupCount_onSecondaryZone_returnsAllGroups() throws Exception {
CarAudioService service = setUpAudioService();
expectWithMessage("Secondary Zone car volume group count")
.that(service.getVolumeGroupCount(TEST_REAR_LEFT_ZONE_ID))
.isEqualTo(SECONDARY_ZONE_VOLUME_GROUP_COUNT);
}
@Test
public void getUsagesForVolumeGroupId_forMusicContext() throws Exception {
CarAudioService service = setUpAudioService();
expectWithMessage("Primary zone's music car volume group id usages")
.that(service.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() throws Exception {
CarAudioService service = setUpAudioService();
int systemVolumeGroup =
service.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE, USAGE_EMERGENCY);
expectWithMessage("Primary zone's system car volume group id usages")
.that(service.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()
throws Exception {
CarAudioService service = setUpAudioService();
expectWithMessage("Secondary Zone's car volume group id usages")
.that(service.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() throws Exception {
CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
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()
throws Exception {
CarAudioService service = setUpAudioService();
doReturn(false)
.when(() -> SystemProperties.getBoolean(PROPERTY_RO_ENABLE_AUDIO_PATCH, false));
IllegalStateException thrown = assertThrows(IllegalStateException.class, () ->
service.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() throws Exception {
CarAudioService service = setUpAudioService();
mockDenyCarControlAudioSettingsPermission();
SecurityException thrown = assertThrows(SecurityException.class,
() -> service
.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() throws Exception {
CarAudioService service = setUpAudioService();
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 = service
.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() throws Exception {
CarAudioService service = setUpAudioService();
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,
() -> service.releaseAudioPatch(carAudioPatchHandle));
expectWithMessage("Release FM and Media Audio Patch Exception")
.that(thrown).hasMessageThat().contains("Audio Patch APIs not enabled");
}
@Test
public void releaseAudioPatch_failsForMissingPermission() throws Exception {
CarAudioService service = setUpAudioService();
mockDenyCarControlAudioSettingsPermission();
CarAudioPatchHandle carAudioPatchHandle =
new CarAudioPatchHandle(0, PRIMARY_ZONE_FM_TUNER_ADDRESS, MEDIA_TEST_DEVICE);
SecurityException thrown = assertThrows(SecurityException.class,
() -> service.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()
throws Exception {
CarAudioService service = setUpAudioService();
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,
() -> service.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() throws Exception {
CarAudioService service = setUpAudioService();
assertThrows(NullPointerException.class,
() -> service.releaseAudioPatch(null));
}
@Test
public void setZoneIdForUid_withoutRoutingPermission_fails() throws Exception {
CarAudioService service = setUpAudioService();
mockDenyCarControlAudioSettingsPermission();
SecurityException thrown = assertThrows(SecurityException.class,
() -> service.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() throws Exception {
CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
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("Non legacy routing is required");
}
@Test
public void setZoneIdForUid_withInvalidZone_fails() throws Exception {
CarAudioService service = setUpAudioService();
IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
() -> service.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() throws Exception {
CarAudioService service = setUpAudioService();
IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
() -> service.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() throws Exception {
CarAudioService service = setUpAudioService();
IllegalStateException thrown = assertThrows(IllegalStateException.class,
() -> service.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 {
CarAudioService noZoneMappingAudioService = setUpCarAudioServiceWithoutZoneMapping();
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 {
CarAudioService noZoneMappingAudioService = setUpCarAudioServiceWithoutZoneMapping();
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 {
CarAudioService noZoneMappingAudioService = setUpCarAudioServiceWithoutZoneMapping();
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 {
CarAudioService noZoneMappingAudioService = setUpCarAudioServiceWithoutZoneMapping();
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 {
CarAudioService noZoneMappingAudioService = setUpCarAudioServiceWithoutZoneMapping();
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 {
CarAudioService noZoneMappingAudioService = setUpCarAudioServiceWithoutZoneMapping();
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() throws Exception {
CarAudioService service = setUpAudioService();
mockDenyCarControlAudioSettingsPermission();
SecurityException thrown = assertThrows(SecurityException.class,
() -> service.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() throws Exception {
CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
IllegalStateException thrown = assertThrows(IllegalStateException.class,
() -> nonDynamicAudioService.clearZoneIdForUid(MEDIA_APP_UID));
expectWithMessage("Clear Zone for UID Dynamic Configuration Exception")
.that(thrown).hasMessageThat()
.contains("Non legacy routing is required");
}
@Test
public void clearZoneIdForUid_withZoneAudioMapping_fails() throws Exception {
CarAudioService service = setUpAudioService();
IllegalStateException thrown = assertThrows(IllegalStateException.class,
() -> service.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 = setUpCarAudioServiceWithoutZoneMapping();
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 {
CarAudioService noZoneMappingAudioService = setUpCarAudioServiceWithoutZoneMapping();
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 {
CarAudioService noZoneMappingAudioService = setUpCarAudioServiceWithoutZoneMapping();
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 {
CarAudioService noZoneMappingAudioService = setUpCarAudioServiceWithoutZoneMapping();
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 {
CarAudioService noZoneMappingAudioService = setUpCarAudioServiceWithoutZoneMapping();
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 {
CarAudioService noZoneMappingAudioService = setUpCarAudioServiceWithoutZoneMapping();
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() throws Exception {
CarAudioService service = setUpAudioService();
mockDenyCarControlAudioVolumePermission();
SecurityException thrown = assertThrows(SecurityException.class,
() -> service.setGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
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() throws Exception {
CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
nonDynamicAudioService.setGroupVolume(
PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0, TEST_GAIN_INDEX, TEST_FLAGS);
verify(mAudioManager).setStreamVolume(
CarAudioDynamicRouting.STREAM_TYPES[TEST_PRIMARY_ZONE_GROUP_0],
TEST_GAIN_INDEX,
TEST_FLAGS);
}
@Test
public void setGroupVolume_verifyNoCallbacks() throws Exception {
CarAudioService service = setUpAudioService();
service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
/* mute= */ false, TEST_FLAGS);
reset(mCarVolumeCallbackHandler);
service.setGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
TEST_GAIN_INDEX, TEST_FLAGS);
verify(mCarVolumeCallbackHandler, never()).onGroupMuteChange(anyInt(), anyInt(), anyInt());
}
@Test
public void setGroupVolume_afterSetVolumeGroupMute() throws Exception {
CarAudioService service = setUpAudioService();
service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
/* mute= */ true, TEST_FLAGS);
reset(mCarVolumeCallbackHandler);
service.setGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
TEST_GAIN_INDEX, TEST_FLAGS);
verify(mCarVolumeCallbackHandler).onGroupMuteChange(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0, TEST_FLAGS);
}
@Test
public void setGroupVolume_withVolumeGroupMutingDisabled_doesnotThrowException()
throws Exception {
CarAudioService nonVolumeGroupMutingAudioService =
setUpAudioServiceWithDisabledResource(audioUseCarVolumeGroupMuting);
HalAudioGainCallback callback = getHalAudioGainCallback();
CarAudioGainConfigInfo carGain = createCarAudioGainConfigInfo(PRIMARY_AUDIO_ZONE,
MEDIA_TEST_DEVICE, TEST_GAIN_INDEX);
callback.onAudioDeviceGainsChanged(List.of(Reasons.TCU_MUTE), List.of(carGain));
reset(mCarVolumeCallbackHandler);
nonVolumeGroupMutingAudioService.setGroupVolume(
PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0, TEST_GAIN_INDEX, TEST_FLAGS);
// if an exception is thrown, the test automatically fails
verify(mCarVolumeCallbackHandler).onVolumeGroupChange(eq(PRIMARY_AUDIO_ZONE),
eq(TEST_PRIMARY_ZONE_GROUP_0), anyInt());
verify(mCarVolumeCallbackHandler, never()).onGroupMuteChange(anyInt(), anyInt(), anyInt());
}
@Test
public void getOutputDeviceAddressForUsage_forMusicUsage() throws Exception {
CarAudioService service = setUpAudioService();
String mediaDeviceAddress =
service.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()
throws Exception {
when(mMockResources.getBoolean(audioUseCoreRouting)).thenReturn(false);
CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
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("Non legacy routing is required");
}
@Test
public void getOutputDeviceAddressForUsage_forNavigationUsage() throws Exception {
CarAudioService service = setUpAudioService();
String mediaDeviceAddress =
service.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() throws Exception {
CarAudioService service = setUpAudioService();
IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
service.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() throws Exception {
CarAudioService service = setUpAudioService();
IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
service.getOutputDeviceAddressForUsage(PRIMARY_AUDIO_ZONE,
AudioManagerHelper.getUsageVirtualSource()));
expectWithMessage("Invalid context audio device address exception")
.that(thrown).hasMessageThat()
.contains("invalid");
}
@Test
public void getOutputDeviceAddressForUsage_onSecondaryZone_forMusicUsage() throws Exception {
CarAudioService service = setUpAudioService();
String mediaDeviceAddress = service.getOutputDeviceAddressForUsage(
TEST_REAR_LEFT_ZONE_ID, USAGE_MEDIA);
expectWithMessage("Media usage audio device address for secondary zone")
.that(mediaDeviceAddress).isEqualTo(SECONDARY_TEST_DEVICE_CONFIG_0);
}
@Test
public void getSuggestedAudioContextForZone_inPrimaryZone() throws Exception {
CarAudioService service = setUpAudioService();
int defaultAudioContext = service.getCarAudioContext()
.getContextForAudioAttribute(CAR_DEFAULT_AUDIO_ATTRIBUTE);
expectWithMessage("Suggested audio context for primary zone")
.that(service.getSuggestedAudioContextForZone(PRIMARY_AUDIO_ZONE))
.isEqualTo(defaultAudioContext);
}
@Test
public void getSuggestedAudioContextForZone_inSecondaryZone() throws Exception {
CarAudioService service = setUpAudioService();
int defaultAudioContext = service.getCarAudioContext()
.getContextForAudioAttribute(CAR_DEFAULT_AUDIO_ATTRIBUTE);
expectWithMessage("Suggested audio context for secondary zone")
.that(service.getSuggestedAudioContextForZone(TEST_REAR_LEFT_ZONE_ID))
.isEqualTo(defaultAudioContext);
}
@Test
public void getSuggestedAudioContextForZone_inInvalidZone() throws Exception {
CarAudioService service = setUpAudioService();
expectWithMessage("Suggested audio context for invalid zone")
.that(service.getSuggestedAudioContextForZone(INVALID_AUDIO_ZONE))
.isEqualTo(CarAudioContext.getInvalidContext());
}
@Test
public void isVolumeGroupMuted_noSetVolumeGroupMute() throws Exception {
CarAudioService service = setUpAudioService();
expectWithMessage("Volume group mute for default state")
.that(service.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0)).isFalse();
}
@Test
public void isVolumeGroupMuted_setVolumeGroupMuted_isFalse() throws Exception {
CarAudioService service = setUpAudioService();
service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
/* mute= */ true, TEST_FLAGS);
service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
/* mute= */ false, TEST_FLAGS);
expectWithMessage("Volume group muted after mute and unmute")
.that(service.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0)).isFalse();
}
@Test
public void isVolumeGroupMuted_setVolumeGroupMuted_isTrue() throws Exception {
CarAudioService service = setUpAudioService();
service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
/* mute= */ true, TEST_FLAGS);
expectWithMessage("Volume group muted after mute")
.that(service.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0)).isTrue();
}
@Test
public void isVolumeGroupMuted_withVolumeGroupMutingDisabled() throws Exception {
when(mMockResources.getBoolean(audioUseCarVolumeGroupMuting)).thenReturn(false);
CarAudioService nonVolumeGroupMutingAudioService =
setUpAudioServiceWithDisabledResource(audioUseCarVolumeGroupMuting);
expectWithMessage("Volume group for disabled volume group muting")
.that(nonVolumeGroupMutingAudioService.isVolumeGroupMuted(
PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0))
.isFalse();
}
@Test
public void getGroupMaxVolume_forPrimaryZone() throws Exception {
CarAudioService service = setUpAudioService();
expectWithMessage("Group max volume for primary audio zone and group")
.that(service.getGroupMaxVolume(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0)).isEqualTo((MAX_GAIN - MIN_GAIN) / STEP_SIZE);
}
@Test
public void getGroupMinVolume_forPrimaryZone() throws Exception {
CarAudioService service = setUpAudioService();
expectWithMessage("Group Min Volume for primary audio zone and group")
.that(service.getGroupMinVolume(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0)).isEqualTo(0);
}
@Test
public void getGroupCurrentVolume_forPrimaryZone() throws Exception {
CarAudioService service = setUpAudioService();
expectWithMessage("Current group volume for primary audio zone and group")
.that(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0))
.isEqualTo((DEFAULT_GAIN - MIN_GAIN) / STEP_SIZE);
}
@Test
public void getGroupMaxVolume_withNoDynamicRouting() throws Exception {
CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
nonDynamicAudioService.getGroupMaxVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0);
verify(mAudioManager).getStreamMaxVolume(
CarAudioDynamicRouting.STREAM_TYPES[TEST_PRIMARY_ZONE_GROUP_0]);
}
@Test
public void getGroupMinVolume_withNoDynamicRouting() throws Exception {
CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
nonDynamicAudioService.getGroupMinVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0);
verify(mAudioManager).getStreamMinVolume(
CarAudioDynamicRouting.STREAM_TYPES[TEST_PRIMARY_ZONE_GROUP_0]);
}
@Test
public void getGroupCurrentVolume_withNoDynamicRouting() throws Exception {
CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
nonDynamicAudioService.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0);
verify(mAudioManager).getStreamVolume(
CarAudioDynamicRouting.STREAM_TYPES[TEST_PRIMARY_ZONE_GROUP_0]);
}
@Test
public void setBalanceTowardRight_nonNullValue() throws Exception {
CarAudioService service = setUpAudioService();
service.setBalanceTowardRight(TEST_VALUE);
verify(mAudioControlWrapperAidl).setBalanceTowardRight(TEST_VALUE);
}
@Test
public void setBalanceTowardRight_throws() throws Exception {
CarAudioService service = setUpAudioService();
IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, ()
-> service.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() throws Exception {
CarAudioService service = setUpAudioService();
service.setFadeTowardFront(TEST_VALUE);
verify(mAudioControlWrapperAidl).setFadeTowardFront(TEST_VALUE);
}
@Test
public void setFadeTowardFront_throws() throws Exception {
CarAudioService service = setUpAudioService();
IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, ()
-> service.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() throws Exception {
CarAudioService service = setUpAudioService();
expectWithMessage("Dynamic routing audio feature")
.that(service.isAudioFeatureEnabled(AUDIO_FEATURE_DYNAMIC_ROUTING))
.isEqualTo(mUseDynamicRouting);
}
@Test
public void isAudioFeatureEnabled_forDisabledDynamicRouting() throws Exception {
CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
expectWithMessage("Disabled dynamic routing audio feature")
.that(nonDynamicAudioService.isAudioFeatureEnabled(AUDIO_FEATURE_DYNAMIC_ROUTING))
.isFalse();
}
@Test
public void isAudioFeatureEnabled_forVolumeGroupMuting() throws Exception {
CarAudioService service = setUpAudioService();
expectWithMessage("Group muting audio feature")
.that(service.isAudioFeatureEnabled(AUDIO_FEATURE_VOLUME_GROUP_MUTING))
.isEqualTo(mUseCarVolumeGroupMuting);
}
@Test
public void isAudioFeatureEnabled_forDisabledVolumeGroupMuting() throws Exception {
CarAudioService nonVolumeGroupMutingAudioService =
setUpAudioServiceWithDisabledResource(audioUseCarVolumeGroupMuting);
expectWithMessage("Disabled group muting audio feature")
.that(nonVolumeGroupMutingAudioService
.isAudioFeatureEnabled(AUDIO_FEATURE_VOLUME_GROUP_MUTING))
.isFalse();
}
@Test
public void isAudioFeatureEnabled_forVolumeGroupEvent() throws Exception {
CarAudioService service = setUpAudioService();
expectWithMessage("Group events audio feature")
.that(service.isAudioFeatureEnabled(AUDIO_FEATURE_VOLUME_GROUP_EVENTS))
.isEqualTo(mUseCarVolumeGroupEvents);
}
@Test
public void isAudioFeatureEnabled_forDisabledVolumeGroupEvent() throws Exception {
CarAudioService nonVolumeGroupEventsAudioService =
setUpAudioServiceWithDisabledResource(audioUseCarVolumeGroupEvent);
expectWithMessage("Disabled group event audio feature")
.that(nonVolumeGroupEventsAudioService
.isAudioFeatureEnabled(AUDIO_FEATURE_VOLUME_GROUP_EVENTS))
.isFalse();
}
@Test
public void isAudioFeatureEnabled_forUnrecognizableAudioFeature_throws() throws Exception {
CarAudioService service = setUpAudioService();
IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
() -> service.isAudioFeatureEnabled(INVALID_AUDIO_FEATURE));
expectWithMessage("Unknown audio feature")
.that(thrown).hasMessageThat()
.contains("Unknown Audio Feature type: " + INVALID_AUDIO_FEATURE);
}
@Test
public void isAudioFeatureEnabled_forDisabledOemService() throws Exception {
CarAudioService service = setUpAudioService();
boolean isEnabled =
service.isAudioFeatureEnabled(AUDIO_FEATURE_OEM_AUDIO_SERVICE);
expectWithMessage("Oem service enabled with disabled oem service")
.that(isEnabled).isFalse();
}
@Test
public void isAudioFeatureEnabled_withEnabledFocusService() throws Exception {
CarOemAudioFocusProxyService focusProxyService = mock(CarOemAudioFocusProxyService.class);
when(mMockCarOemProxyService.isOemServiceEnabled()).thenReturn(true);
when(mMockCarOemProxyService.getCarOemAudioFocusService()).thenReturn(focusProxyService);
CarAudioService service = setUpAudioService();
boolean isEnabled =
service.isAudioFeatureEnabled(AUDIO_FEATURE_OEM_AUDIO_SERVICE);
expectWithMessage("Oem service enabled with enabled focus service")
.that(isEnabled).isTrue();
}
@Test
public void isAudioFeatureEnabled_withEnabledVolumeService() throws Exception {
CarOemAudioVolumeProxyService volumeProxyService =
mock(CarOemAudioVolumeProxyService.class);
when(mMockCarOemProxyService.isOemServiceEnabled()).thenReturn(true);
when(mMockCarOemProxyService.getCarOemAudioVolumeService()).thenReturn(volumeProxyService);
CarAudioService service = setUpAudioService();
boolean isEnabled =
service.isAudioFeatureEnabled(AUDIO_FEATURE_OEM_AUDIO_SERVICE);
expectWithMessage("Oem service enabled with enabled volume service")
.that(isEnabled).isTrue();
}
@Test
public void isAudioFeatureEnabled_withEnabledDuckingService() throws Exception {
CarOemAudioDuckingProxyService duckingProxyService =
mock(CarOemAudioDuckingProxyService.class);
when(mMockCarOemProxyService.isOemServiceEnabled()).thenReturn(true);
when(mMockCarOemProxyService.getCarOemAudioDuckingService())
.thenReturn(duckingProxyService);
CarAudioService service = setUpAudioService();
boolean isEnabled = service.isAudioFeatureEnabled(AUDIO_FEATURE_OEM_AUDIO_SERVICE);
expectWithMessage("Oem service enabled with enabled ducking service")
.that(isEnabled).isTrue();
}
@Test
public void isAudioFeatureEnabled_withEnabledAudioMirror() throws Exception {
CarAudioService service = setUpAudioService();
boolean isEnabled = service.isAudioFeatureEnabled(AUDIO_FEATURE_AUDIO_MIRRORING);
expectWithMessage("Audio mirror enabled status")
.that(isEnabled).isTrue();
}
@Test
public void isAudioFeatureEnabled_withDisabledAudioMirror() throws Exception {
CarAudioService service = setUpCarAudioServiceWithoutMirroring();
boolean isEnabled = service.isAudioFeatureEnabled(AUDIO_FEATURE_AUDIO_MIRRORING);
expectWithMessage("Audio mirror enabled status")
.that(isEnabled).isFalse();
}
@Test
public void onOccupantZoneConfigChanged_noUserAssignedToPrimaryZone() throws Exception {
CarAudioService service = setUpAudioService();
when(mMockOccupantZoneService.getDriverUserId()).thenReturn(UserManagerHelper.USER_NULL);
when(mMockOccupantZoneService.getUserForOccupant(anyInt()))
.thenReturn(UserManagerHelper.USER_NULL);
ICarOccupantZoneCallback callback = getOccupantZoneCallback();
int prevUserId = service.getUserIdForZone(PRIMARY_AUDIO_ZONE);
callback.onOccupantZoneConfigChanged(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
expectWithMessage("User ID before config changed")
.that(service.getUserIdForZone(PRIMARY_AUDIO_ZONE))
.isEqualTo(prevUserId);
}
@Test
public void onOccupantZoneConfigChanged_userAssignedToPrimaryZone() throws Exception {
CarAudioService service = setUpAudioService();
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(service.getUserIdForZone(PRIMARY_AUDIO_ZONE))
.isEqualTo(TEST_REAR_LEFT_USER_ID);
}
@Test
public void onOccupantZoneConfigChanged_afterResettingUser_returnNoUser() throws Exception {
CarAudioService service = setUpAudioService();
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(service.getUserIdForZone(PRIMARY_AUDIO_ZONE))
.isEqualTo(UserManagerHelper.USER_NULL);
}
@Test
public void onOccupantZoneConfigChanged_noOccupantZoneMapping() throws Exception {
setUpCarAudioServiceWithoutZoneMapping();
ICarOccupantZoneCallback callback = getOccupantZoneCallback();
callback.onOccupantZoneConfigChanged(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
verify(mMockOccupantZoneService, never()).getUserForOccupant(anyInt());
}
@Test
public void onOccupantZoneConfigChanged_noOccupantZoneMapping_alreadyAssigned()
throws Exception {
when(mMockOccupantZoneService.getDriverUserId()).thenReturn(TEST_DRIVER_USER_ID);
CarAudioService noZoneMappingAudioService = setUpCarAudioServiceWithoutZoneMapping();
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 {
CarAudioService service = setUpAudioService();
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(service.getUserIdForZone(PRIMARY_AUDIO_ZONE))
.isNotEqualTo(service.getUserIdForZone(TEST_REAR_LEFT_ZONE_ID));
expectWithMessage("Secondary user ID config changed")
.that(service.getUserIdForZone(TEST_REAR_LEFT_ZONE_ID))
.isEqualTo(TEST_REAR_RIGHT_USER_ID);
}
@Test
public void serviceDied_registersAudioGainCallback() throws Exception {
setUpAudioService();
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() throws Exception {
setUpAudioService();
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() throws Exception {
setUpAudioService();
ArgumentCaptor<AudioControlDeathRecipient> captor =
ArgumentCaptor.forClass(AudioControlDeathRecipient.class);
verify(mAudioControlWrapperAidl).linkToDeath(captor.capture());
AudioControlDeathRecipient runnable = captor.getValue();
reset(mAudioControlWrapperAidl);
runnable.serviceDied();
verify(mAudioControlWrapperAidl).setModuleChangeCallback(any());
}
@Test
public void getVolumeGroupIdForAudioContext_forPrimaryGroup() throws Exception {
CarAudioService service = setUpAudioService();
expectWithMessage("Volume group ID for primary audio zone")
.that(service.getVolumeGroupIdForAudioContext(PRIMARY_AUDIO_ZONE,
CarAudioContext.MUSIC))
.isEqualTo(TEST_PRIMARY_ZONE_GROUP_0);
}
@Test
public void getVolumeGroupIdForAudioAttribute() throws Exception {
CarAudioService service = setUpAudioService();
expectWithMessage("Volume group ID for primary audio zone")
.that(service.getVolumeGroupIdForAudioAttribute(PRIMARY_AUDIO_ZONE,
CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA)))
.isEqualTo(TEST_PRIMARY_ZONE_GROUP_0);
}
@Test
public void getVolumeGroupIdForAudioAttribute_withNullAttribute_fails() throws Exception {
CarAudioService service = setUpAudioService();
NullPointerException thrown = assertThrows(NullPointerException.class, () ->
service.getVolumeGroupIdForAudioAttribute(PRIMARY_AUDIO_ZONE,
/* attribute= */ null));
expectWithMessage("Null audio attribute exception").that(thrown).hasMessageThat()
.contains("Audio attributes");
}
@Test
public void getVolumeGroupIdForAudioAttribute_withInvalidZoneId_fails() throws Exception {
CarAudioService service = setUpAudioService();
IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
service.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() throws Exception {
CarAudioService service = setUpAudioService();
expectWithMessage("Get input device for primary zone id")
.that(service.getInputDevicesForZoneId(PRIMARY_AUDIO_ZONE))
.containsExactly(new AudioDeviceAttributes(mMicrophoneInputDevice));
}
@Test
public void getExternalSources_forSingleDevice() throws Exception {
CarAudioService service = setUpAudioService();
AudioDeviceInfo[] inputDevices = generateInputDeviceInfos();
expectWithMessage("External input device addresses")
.that(service.getExternalSources())
.asList().containsExactly(inputDevices[1].getAddress());
}
@Test
public void setAudioEnabled_forEnabledVolumeGroupMuting() throws Exception {
CarAudioService service = setUpAudioService();
service.setAudioEnabled(/* isAudioEnabled= */ true);
verify(mAudioControlWrapperAidl).onDevicesToMuteChange(any());
}
@Test
public void setAudioEnabled_forDisabledVolumeGroupMuting() throws Exception {
CarAudioService nonVolumeGroupMutingAudioService =
setUpAudioServiceWithDisabledResource(audioUseCarVolumeGroupMuting);
nonVolumeGroupMutingAudioService.setAudioEnabled(/* isAudioEnabled= */ true);
verify(mAudioControlWrapperAidl, never()).onDevicesToMuteChange(any());
}
@Test
public void onAudioServerDown_forCarAudioServiceCallback() throws Exception {
setUpAudioService();
AudioServerStateCallback callback = getAudioServerStateCallback();
callback.onAudioServerDown();
verify(mAudioControlWrapperAidl).onDevicesToMuteChange(any());
}
@Test
public void onAudioServerUp_forCarAudioServiceCallback() throws Exception {
CarAudioService service = setUpAudioService();
AudioServerStateCallback callback = getAudioServerStateCallback();
callback.onAudioServerDown();
callback.onAudioServerUp();
expectWithMessage("Re-initialized Car Audio Service Zones")
.that(service.getAudioZoneIds()).asList()
.containsExactly(PRIMARY_AUDIO_ZONE, TEST_REAR_LEFT_ZONE_ID,
TEST_REAR_RIGHT_ZONE_ID, TEST_FRONT_ZONE_ID, TEST_REAR_ROW_3_ZONE_ID);
}
@Test
public void registerVolumeCallback_verifyCallbackHandler() throws Exception {
int uid = Binder.getCallingUid();
CarAudioService service = setUpAudioService();
service.registerVolumeCallback(mVolumeCallbackBinder);
verify(mCarVolumeCallbackHandler).registerCallback(mVolumeCallbackBinder, uid, true);
}
@Test
public void unregisterVolumeCallback_verifyCallbackHandler() throws Exception {
int uid = Binder.getCallingUid();
CarAudioService service = setUpAudioService();
service.unregisterVolumeCallback(mVolumeCallbackBinder);
verify(mCarVolumeCallbackHandler).unregisterCallback(mVolumeCallbackBinder, uid);
}
@Test
public void getMutedVolumeGroups_forInvalidZone() throws Exception {
CarAudioService service = setUpAudioService();
expectWithMessage("Muted volume groups for invalid zone")
.that(service.getMutedVolumeGroups(INVALID_AUDIO_ZONE))
.isEmpty();
}
@Test
public void getMutedVolumeGroups_whenVolumeGroupMuteNotSupported() throws Exception {
CarAudioService nonVolumeGroupMutingAudioService =
setUpAudioServiceWithDisabledResource(audioUseCarVolumeGroupMuting);
expectWithMessage("Muted volume groups with disable mute feature")
.that(nonVolumeGroupMutingAudioService.getMutedVolumeGroups(PRIMARY_AUDIO_ZONE))
.isEmpty();
}
@Test
public void getMutedVolumeGroups_withMutedGroups() throws Exception {
CarAudioService service = setUpAudioService();
service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
/* muted= */ true, TEST_FLAGS);
service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_1,
/* muted= */ true, TEST_FLAGS);
expectWithMessage("Muted volume groups")
.that(service.getMutedVolumeGroups(PRIMARY_AUDIO_ZONE))
.containsExactly(mTestPrimaryZoneVolumeInfo0,
mTestPrimaryZoneVolumeInfo1);
}
@Test
public void getMutedVolumeGroups_afterUnmuting() throws Exception {
CarAudioService service = setUpAudioService();
service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
/* mute= */ true, TEST_FLAGS);
service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_1,
/* mute= */ true, TEST_FLAGS);
service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
/* mute= */ false, TEST_FLAGS);
expectWithMessage("Muted volume groups after unmuting one group")
.that(service.getMutedVolumeGroups(PRIMARY_AUDIO_ZONE))
.containsExactly(mTestPrimaryZoneVolumeInfo1);
}
@Test
public void getMutedVolumeGroups_withMutedGroupsForDifferentZone() throws Exception {
CarAudioService service = setUpAudioService();
service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
/* muted= */ true, TEST_FLAGS);
service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_1,
/* muted= */ true, TEST_FLAGS);
expectWithMessage("Muted volume groups for secondary zone")
.that(service.getMutedVolumeGroups(TEST_REAR_LEFT_ZONE_ID)).isEmpty();
}
@Test
public void onReceive_forLegacy_noCallToOnVolumeGroupChanged() throws Exception {
setUpAudioServiceWithoutDynamicRouting();
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() throws Exception {
setUpAudioServiceWithoutDynamicRouting();
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() throws Exception {
setUpAudioServiceWithoutDynamicRouting();
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() throws Exception {
CarAudioService service = setUpAudioService();
int groupCount = service.getVolumeGroupCount(PRIMARY_AUDIO_ZONE);
List<CarVolumeGroupInfo> infos =
service.getVolumeGroupInfosForZone(PRIMARY_AUDIO_ZONE);
for (int index = 0; index < groupCount; index++) {
CarVolumeGroupInfo info = service
.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() throws Exception {
CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
List<CarVolumeGroupInfo> infos =
nonDynamicAudioService.getVolumeGroupInfosForZone(PRIMARY_AUDIO_ZONE);
expectWithMessage("Car volume group infos with dynamic routing disabled")
.that(infos).isEmpty();
}
@Test
public void getVolumeGroupInfosForZone_forOEMConfiguration() throws Exception {
setUpTempFileForAudioConfiguration(R.raw.car_audio_configuration_using_oem_defined_context);
CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext,
mTempCarAudioConfigFile.getFile().getAbsolutePath(), mCarVolumeCallbackHandler);
nonDynamicAudioService.init();
List<CarVolumeGroupInfo> infos =
nonDynamicAudioService.getVolumeGroupInfosForZone(PRIMARY_AUDIO_ZONE);
expectWithMessage("Car volume group infos size with OEM configuration")
.that(infos).hasSize(1);
expectWithMessage("Car volume group info name with OEM configuration")
.that(infos.get(0).getName()).isEqualTo("OEM_VOLUME_GROUP");
}
@Test
public void getVolumeGroupInfosForZone_size() throws Exception {
CarAudioService service = setUpAudioService();
int groupCount = service.getVolumeGroupCount(PRIMARY_AUDIO_ZONE);
List<CarVolumeGroupInfo> infos =
service.getVolumeGroupInfosForZone(PRIMARY_AUDIO_ZONE);
expectWithMessage("Car volume group infos size for primary zone")
.that(infos).hasSize(groupCount);
}
@Test
public void getVolumeGroupInfosForZone_forInvalidZone() throws Exception {
CarAudioService service = setUpAudioService();
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () ->
service.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() throws Exception {
CarVolumeGroupInfo testVolumeGroupInfo = new CarVolumeGroupInfo.Builder(
mTestPrimaryZoneVolumeInfo0).setMuted(false).build();
CarAudioService service = setUpAudioService();
expectWithMessage("Car volume group info for primary zone")
.that(service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0)).isEqualTo(testVolumeGroupInfo);
}
@Test
public void getVolumeGroupInfo_forInvalidZone() throws Exception {
CarAudioService service = setUpAudioService();
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () ->
service.getVolumeGroupInfo(INVALID_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0));
expectWithMessage("Exception for volume group info size for invalid zone")
.that(thrown).hasMessageThat().contains("audio zone Id");
}
@Test
public void getVolumeGroupInfo_forInvalidGroup() throws Exception {
CarAudioService service = setUpAudioService();
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () ->
service.getVolumeGroupInfo(INVALID_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0));
expectWithMessage("Exception for volume groups info size for invalid group id")
.that(thrown).hasMessageThat().contains("audio zone Id");
}
@Test
public void getVolumeGroupInfo_forGroupOverRange() throws Exception {
CarAudioService service = setUpAudioService();
int groupCount = service.getVolumeGroupCount(PRIMARY_AUDIO_ZONE);
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () ->
service.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()
throws Exception {
CarAudioService service = setUpAudioService();
NullPointerException thrown = assertThrows(NullPointerException.class, ()
-> service.registerPrimaryZoneMediaAudioRequestCallback(
/* callback= */ null));
expectWithMessage("Register audio media request callback exception")
.that(thrown).hasMessageThat()
.contains("Media request callback");
}
@Test
public void unregisterPrimaryZoneMediaAudioRequestCallback_withNullCallback_fails()
throws Exception {
CarAudioService service = setUpAudioService();
NullPointerException thrown = assertThrows(NullPointerException.class, ()
-> service.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 {
CarAudioService service = setUpAudioService();
TestPrimaryZoneMediaAudioRequestCallback
requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
assignOccupantToAudioZones();
service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
expectWithMessage("Audio media request id")
.that(service.requestMediaAudioOnPrimaryZone(requestCallback,
TEST_REAR_RIGHT_PASSENGER_OCCUPANT))
.isNotEqualTo(INVALID_REQUEST_ID);
}
@Test
public void requestMediaAudioOnPrimaryZone_withDriverOccupant_fails()
throws Exception {
CarAudioService service = setUpAudioService();
TestPrimaryZoneMediaAudioRequestCallback
requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
assignOccupantToAudioZones();
service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, ()
-> service.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(OUT_OF_RANGE_ZONE);
CarAudioService service = setUpAudioService();
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();
service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
expectWithMessage("Invalid audio media request id")
.that(service.requestMediaAudioOnPrimaryZone(requestCallback, info))
.isEqualTo(INVALID_REQUEST_ID);
}
@Test
public void requestMediaAudioOnPrimaryZone_withPassengerOccupant_callsApprover()
throws Exception {
CarAudioService service = setUpAudioService();
TestPrimaryZoneMediaAudioRequestCallback
requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
assignOccupantToAudioZones();
service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
long requestId = service.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 requestMediaAudioOnPrimaryZone_withZoneMirroring_fails()
throws Exception {
CarAudioService service = setUpAudioService();
TestPrimaryZoneMediaAudioRequestCallback
requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
assignOccupantToAudioZones();
service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
TestAudioZonesMirrorStatusCallbackCallback mirrorCallback =
getAudioZonesMirrorStatusCallback(service);
service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
mirrorCallback.waitForCallback();
IllegalStateException thrown = assertThrows(IllegalStateException.class, () ->
service.requestMediaAudioOnPrimaryZone(requestCallback,
TEST_REAR_RIGHT_PASSENGER_OCCUPANT));
expectWithMessage("Request audio share while mirroring exception").that(thrown)
.hasMessageThat().contains("Can not request audio share to primary zone");
}
@Test
public void binderDied_onMediaRequestApprover_resetsApprovedRequest()
throws Exception {
CarAudioService service = setUpAudioService();
TestPrimaryZoneMediaAudioRequestCallback requestToken =
new TestPrimaryZoneMediaAudioRequestCallback();
TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
assignOccupantToAudioZones();
service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
requestToken.waitForCallback();
requestToken.reset();
service.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allow= */ true);
requestToken.waitForCallback();
requestCallback.waitForCallback();
requestCallback.reset();
requestToken.mDeathRecipient.binderDied();
requestCallback.waitForCallback();
expectWithMessage("Stopped status due to approver's death").that(requestCallback.mStatus)
.isEqualTo(CarAudioManager.AUDIO_REQUEST_STATUS_STOPPED);
expectWithMessage("Stopped id due to approver's death")
.that(requestCallback.mRequestId).isEqualTo(requestId);
}
@Test
public void allowMediaAudioOnPrimaryZone_withAllowedRequest() throws Exception {
CarAudioService service = setUpAudioService();
TestPrimaryZoneMediaAudioRequestCallback
requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
assignOccupantToAudioZones();
service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
requestToken.waitForCallback();
boolean results = service.allowMediaAudioOnPrimaryZone(requestToken, requestId,
/* allow= */ true);
expectWithMessage("Allowed audio playback").that(results).isTrue();
}
@Test
public void allowMediaAudioOnPrimaryZone_whileMirroring_fails() throws Exception {
CarAudioService service = setUpAudioService();
TestPrimaryZoneMediaAudioRequestCallback
requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
assignOccupantToAudioZones();
service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
long shareId = service.requestMediaAudioOnPrimaryZone(requestCallback,
TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
requestToken.waitForCallback();
TestAudioZonesMirrorStatusCallbackCallback mirrorCallback =
getAudioZonesMirrorStatusCallback(service);
service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
mirrorCallback.waitForCallback();
requestCallback.waitForCallback();
IllegalStateException thrown =
assertThrows(IllegalStateException.class, () -> service
.allowMediaAudioOnPrimaryZone(requestToken, shareId, /* allow= */ true));
expectWithMessage("Allow audio share while mirroring exception").that(thrown)
.hasMessageThat().contains("Can not allow audio share to primary zone");
requestCallback.waitForCallback();
expectWithMessage("Rejected status due to mirroring").that(requestCallback.mStatus)
.isEqualTo(CarAudioManager.AUDIO_REQUEST_STATUS_REJECTED);
expectWithMessage("Rejected id with rejected due to mirroring")
.that(requestCallback.mRequestId).isEqualTo(shareId);
}
@Test
public void allowMediaAudioOnPrimaryZone_withUnallowedRequest() throws Exception {
CarAudioService service = setUpAudioService();
TestPrimaryZoneMediaAudioRequestCallback
requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
assignOccupantToAudioZones();
service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
requestToken.waitForCallback();
boolean results = service.allowMediaAudioOnPrimaryZone(requestToken, requestId,
/* allow= */ false);
expectWithMessage("Unallowed audio playback").that(results).isTrue();
}
@Test
public void allowMediaAudioOnPrimaryZone_withAllowedRequest_callsRequester() throws Exception {
CarAudioService service = setUpAudioService();
TestPrimaryZoneMediaAudioRequestCallback
requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
assignOccupantToAudioZones();
service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
requestToken.waitForCallback();
service.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allow= */ 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 {
CarAudioService service = setUpAudioService();
TestPrimaryZoneMediaAudioRequestCallback
requestApprover = new TestPrimaryZoneMediaAudioRequestCallback();
TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
assignOccupantToAudioZones();
service.registerPrimaryZoneMediaAudioRequestCallback(requestApprover);
long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
requestApprover.waitForCallback();
requestApprover.reset();
service.allowMediaAudioOnPrimaryZone(requestApprover, requestId, /* allow= */ 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 {
CarAudioService service = setUpAudioService();
TestPrimaryZoneMediaAudioRequestCallback
requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
assignOccupantToAudioZones();
service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
requestToken.waitForCallback();
service.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allow= */ 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 {
CarAudioService service = setUpAudioService();
TestPrimaryZoneMediaAudioRequestCallback
requestApprover = new TestPrimaryZoneMediaAudioRequestCallback();
TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
assignOccupantToAudioZones();
service.registerPrimaryZoneMediaAudioRequestCallback(requestApprover);
long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
requestApprover.waitForCallback();
requestApprover.reset();
service.allowMediaAudioOnPrimaryZone(requestApprover, requestId, /* allow= */ 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 {
CarAudioService service = setUpAudioService();
NullPointerException thrown = assertThrows(NullPointerException.class, ()
-> service.isMediaAudioAllowedInPrimaryZone(/* info= */ null));
expectWithMessage("Media status exception").that(thrown)
.hasMessageThat().contains("Occupant zone info");
}
@Test
public void isMediaAudioAllowedInPrimaryZone_byDefault() throws Exception {
CarAudioService service = setUpAudioService();
expectWithMessage("Media default status")
.that(service.isMediaAudioAllowedInPrimaryZone(
TEST_REAR_RIGHT_PASSENGER_OCCUPANT))
.isFalse();
}
@Test
public void isMediaAudioAllowedInPrimaryZone_afterAllowed() throws Exception {
CarAudioService service = setUpAudioService();
TestPrimaryZoneMediaAudioRequestCallback
requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
assignOccupantToAudioZones();
service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
requestToken.waitForCallback();
requestToken.reset();
service.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allow= */ true);
requestToken.waitForCallback();
expectWithMessage("Media allowed status")
.that(service.isMediaAudioAllowedInPrimaryZone(
TEST_REAR_RIGHT_PASSENGER_OCCUPANT))
.isTrue();
}
@Test
public void isMediaAudioAllowedInPrimaryZone_afterDisallowed() throws Exception {
CarAudioService service = setUpAudioService();
TestPrimaryZoneMediaAudioRequestCallback
requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
assignOccupantToAudioZones();
service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
requestToken.waitForCallback();
requestToken.reset();
service.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allow= */ false);
requestToken.waitForCallback();
expectWithMessage("Media after disallowed status")
.that(service.isMediaAudioAllowedInPrimaryZone(
TEST_REAR_RIGHT_PASSENGER_OCCUPANT))
.isFalse();
}
@Test
public void isMediaAudioAllowedInPrimaryZone_afterUserLogout() throws Exception {
CarAudioService service = setUpAudioService();
TestPrimaryZoneMediaAudioRequestCallback
requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
assignOccupantToAudioZones();
service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
requestToken.waitForCallback();
requestToken.reset();
service.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allow= */ true);
requestToken.waitForCallback();
requestToken.reset();
simulateLogoutPassengers();
requestToken.waitForCallback();
expectWithMessage("Media allowed status after passenger logout")
.that(service.isMediaAudioAllowedInPrimaryZone(
TEST_REAR_RIGHT_PASSENGER_OCCUPANT)).isFalse();
}
@Test
public void isMediaAudioAllowedInPrimaryZone_afterUserSwitch() throws Exception {
CarAudioService service = setUpAudioService();
TestPrimaryZoneMediaAudioRequestCallback
requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
assignOccupantToAudioZones();
service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
requestToken.waitForCallback();
requestToken.reset();
service.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allow= */ true);
requestToken.waitForCallback();
requestToken.reset();
simulatePassengersSwitch();
requestToken.waitForCallback();
expectWithMessage("Media allowed status after passenger switch")
.that(service.isMediaAudioAllowedInPrimaryZone(
TEST_REAR_RIGHT_PASSENGER_OCCUPANT)).isFalse();
}
@Test
public void resetMediaAudioOnPrimaryZone_afterAllowed() throws Exception {
CarAudioService service = setUpAudioService();
TestPrimaryZoneMediaAudioRequestCallback
requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
assignOccupantToAudioZones();
service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
requestToken.waitForCallback();
requestToken.reset();
service.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allow= */ true);
requestToken.waitForCallback();
requestToken.reset();
boolean reset = service.resetMediaAudioOnPrimaryZone(
TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
requestToken.waitForCallback();
expectWithMessage("Reset status").that(reset).isTrue();
expectWithMessage("Media reset status")
.that(service.isMediaAudioAllowedInPrimaryZone(
TEST_REAR_RIGHT_PASSENGER_OCCUPANT))
.isFalse();
}
@Test
public void cancelMediaAudioOnPrimaryZone_beforeAllowed() throws Exception {
CarAudioService service = setUpAudioService();
TestPrimaryZoneMediaAudioRequestCallback
requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
assignOccupantToAudioZones();
service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
requestToken.waitForCallback();
requestToken.reset();
boolean cancel = service.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 {
CarAudioService service = setUpAudioService();
TestPrimaryZoneMediaAudioRequestCallback
requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
assignOccupantToAudioZones();
service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
requestToken.waitForCallback();
requestToken.reset();
service.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allow= */ true);
requestToken.waitForCallback();
requestToken.reset();
boolean cancel = service.cancelMediaAudioOnPrimaryZone(requestId);
requestToken.waitForCallback();
expectWithMessage("Cancel status after allowed").that(cancel).isTrue();
expectWithMessage("Media allowed status after canceled")
.that(service.isMediaAudioAllowedInPrimaryZone(
TEST_REAR_RIGHT_PASSENGER_OCCUPANT))
.isFalse();
}
@Test
public void getZoneIdForAudioFocusInfo_beforeAllowedSharedAudio() throws Exception {
CarAudioService service = setUpAudioService();
TestPrimaryZoneMediaAudioRequestCallback
requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
assignOccupantToAudioZones();
service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
service.requestMediaAudioOnPrimaryZone(requestCallback,
TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
requestToken.waitForCallback();
expectWithMessage("Not yet shared media user zone")
.that(service.getZoneIdForAudioFocusInfo(TEST_REAR_RIGHT_AUDIO_FOCUS_INFO))
.isEqualTo(TEST_REAR_RIGHT_ZONE_ID);
}
@Test
public void getZoneIdForAudioFocusInfo_afterAllowedShareAudio() throws Exception {
CarAudioService service = setUpAudioService();
TestPrimaryZoneMediaAudioRequestCallback
requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
assignOccupantToAudioZones();
service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
requestToken.waitForCallback();
requestToken.reset();
service.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allow= */ true);
requestToken.waitForCallback();
expectWithMessage("Shared media user zone")
.that(service.getZoneIdForAudioFocusInfo(TEST_REAR_RIGHT_AUDIO_FOCUS_INFO))
.isEqualTo(PRIMARY_AUDIO_ZONE);
}
@Test
public void getZoneIdForAudioFocusInfo_afterCanceled() throws Exception {
CarAudioService service = setUpAudioService();
TestPrimaryZoneMediaAudioRequestCallback
requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
assignOccupantToAudioZones();
service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
requestToken.waitForCallback();
requestToken.reset();
service.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allow= */ true);
requestToken.waitForCallback();
requestToken.reset();
service.cancelMediaAudioOnPrimaryZone(requestId);
requestToken.waitForCallback();
expectWithMessage("Canceled shared media user zone")
.that(service.getZoneIdForAudioFocusInfo(TEST_REAR_RIGHT_AUDIO_FOCUS_INFO))
.isEqualTo(TEST_REAR_RIGHT_ZONE_ID);
}
@Test
public void getZoneIdForAudioFocusInfo_afterReset() throws Exception {
CarAudioService service = setUpAudioService();
TestPrimaryZoneMediaAudioRequestCallback
requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
assignOccupantToAudioZones();
service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
requestToken.waitForCallback();
requestToken.reset();
service.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allow= */ true);
requestToken.waitForCallback();
requestToken.reset();
service.resetMediaAudioOnPrimaryZone(TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
requestToken.waitForCallback();
expectWithMessage("Reset shared media user zone")
.that(service.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() throws Exception {
CarAudioService service = setUpAudioService();
CarVolumeGroupInfo info = service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0);
List<AudioAttributes> audioAttributes =
service.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() throws Exception {
CarAudioService service = setUpAudioService();
NullPointerException thrown =
assertThrows(NullPointerException.class, () ->
service.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() throws Exception {
CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
List<AudioAttributes> audioAttributes = nonDynamicAudioService
.getAudioAttributesForVolumeGroup(mTestPrimaryZoneVolumeInfo0);
expectWithMessage("Volume group audio attributes with dynamic routing disabled")
.that(audioAttributes).isEmpty();
}
@Test
public void onKeyEvent_forInvalidAudioZone() throws Exception {
CarAudioService service = setUpAudioService();
int volumeBefore = service.getGroupVolume(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0);
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(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0)).isEqualTo(volumeBefore);
}
@Test
public void onKeyEvent_forInvalidEvent() throws Exception {
CarAudioService service = setUpAudioService();
int volumeBefore = service.getGroupVolume(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0);
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(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0)).isEqualTo(volumeBefore);
}
@Test
public void onKeyEvent_forActionUp() throws Exception {
CarAudioService service = setUpAudioService();
int volumeBefore = service.getGroupVolume(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0);
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(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0)).isEqualTo(volumeBefore);
}
@Test
public void onKeyEvent_forActionDownFollowedByActionUp() throws Exception {
CarAudioService service = setUpAudioService();
int volumeBefore = service.getGroupVolume(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0);
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(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0)).isEqualTo(volumeBefore + 1);
}
@Test
public void onKeyEvent_forVolumeUpEvent_inPrimaryZone() throws Exception {
CarAudioService service = setUpAudioService();
int volumeBefore = service.getGroupVolume(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0);
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(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0)).isGreaterThan(volumeBefore);
}
@Test
public void onKeyEvent_forVolumeDownEvent_inPrimaryZone() throws Exception {
CarAudioService service = setUpAudioService();
int volumeBefore = service.getGroupVolume(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0);
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(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0)).isLessThan(volumeBefore);
}
@Test
public void onKeyEvent_forVolumeDownEvent_inPrimaryZone_forSecondaryGroup() throws Exception {
CarAudioService service = setUpAudioService();
int volumeBefore = service.getGroupVolume(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_1);
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(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_1)).isLessThan(volumeBefore);
}
@Test
public void onKeyEvent_forVolumeDownEvent_inPrimaryZone_withHigherPriority() throws Exception {
CarAudioService service = setUpAudioService();
int primaryGroupVolumeBefore = service.getGroupVolume(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0);
int voiceVolumeGroupBefore = service.getGroupVolume(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_2);
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(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0)).isEqualTo(primaryGroupVolumeBefore);
expectWithMessage("Call volume group volume after volume down")
.that(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_2)).isLessThan(voiceVolumeGroupBefore);
}
@Test
public void onKeyEvent_forVolumeDownEvent_inPrimaryZone_withVersionTwoVolumeList()
throws Exception {
CarAudioService service = setUpCarAudioServiceWithVersionTwoVolumeList();
int primaryGroupVolumeBefore = service.getGroupVolume(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0);
int voiceVolumeGroupBefore = service.getGroupVolume(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_2);
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 for volume list two")
.that(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0)).isEqualTo(primaryGroupVolumeBefore);
expectWithMessage("Call volume group volume after volume down for volume list two")
.that(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_2)).isLessThan(voiceVolumeGroupBefore);
}
@Test
public void onKeyEvent_forVolumeMuteEvent_inPrimaryZone() throws Exception {
CarAudioService service = setUpAudioService();
boolean muteBefore = service.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0);
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(service.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0)).isNotEqualTo(muteBefore);
}
@Test
public void onKeyEvent_forVolumeUpEvent_inSecondaryZone() throws Exception {
CarAudioService service = setUpAudioService();
int volumeBefore = service.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(service.getGroupVolume(TEST_REAR_LEFT_ZONE_ID,
SECONDARY_ZONE_VOLUME_GROUP_ID))
.isGreaterThan(volumeBefore);
}
@Test
public void onKeyEvent_forVolumeDownEvent_inSecondaryZone() throws Exception {
CarAudioService service = setUpAudioService();
int volumeBefore = service.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(service.getGroupVolume(TEST_REAR_LEFT_ZONE_ID,
SECONDARY_ZONE_VOLUME_GROUP_ID))
.isLessThan(volumeBefore);
}
@Test
public void onKeyEvent_forVolumeMuteEvent_inSecondaryZone() throws Exception {
CarAudioService service = setUpAudioService();
boolean muteBefore = service.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(service.isVolumeGroupMuted(TEST_REAR_LEFT_ZONE_ID,
SECONDARY_ZONE_VOLUME_GROUP_ID))
.isNotEqualTo(muteBefore);
}
@Test
public void onAudioDeviceGainsChanged_forPrimaryZone_changesVolume() throws Exception {
CarAudioService service = setUpAudioService();
HalAudioGainCallback callback = getHalAudioGainCallback();
CarAudioGainConfigInfo carGain = createCarAudioGainConfigInfo(PRIMARY_AUDIO_ZONE,
MEDIA_TEST_DEVICE, TEST_GAIN_INDEX);
callback.onAudioDeviceGainsChanged(List.of(Reasons.THERMAL_LIMITATION), List.of(carGain));
expectWithMessage("New audio gains for primary zone")
.that(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0)).isEqualTo(TEST_GAIN_INDEX);
}
@Test
public void onAudioDeviceGainsChanged_forSecondaryZone_changesVolume() throws Exception {
CarAudioService service = setUpAudioService();
HalAudioGainCallback callback = getHalAudioGainCallback();
CarAudioGainConfigInfo carGain = createCarAudioGainConfigInfo(TEST_REAR_LEFT_ZONE_ID,
SECONDARY_TEST_DEVICE_CONFIG_0, TEST_GAIN_INDEX);
callback.onAudioDeviceGainsChanged(List.of(Reasons.THERMAL_LIMITATION), List.of(carGain));
expectWithMessage("New audio gains for secondary zone")
.that(service.getGroupVolume(TEST_REAR_LEFT_ZONE_ID,
TEST_PRIMARY_ZONE_GROUP_0)).isEqualTo(TEST_GAIN_INDEX);
}
@Test
public void onAudioDeviceGainsChanged_forIncorrectDeviceAddress_sameVolume() throws Exception {
CarAudioService service = setUpAudioService();
HalAudioGainCallback callback = getHalAudioGainCallback();
int volumeBefore = service.getGroupVolume(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0);
CarAudioGainConfigInfo carGain = createCarAudioGainConfigInfo(PRIMARY_AUDIO_ZONE,
SECONDARY_TEST_DEVICE_CONFIG_0, TEST_GAIN_INDEX);
callback.onAudioDeviceGainsChanged(List.of(Reasons.THERMAL_LIMITATION), List.of(carGain));
expectWithMessage("Same audio gains for primary zone")
.that(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0)).isEqualTo(volumeBefore);
}
@Test
public void onAudioDeviceGainsChanged_forMultipleZones_changesVolume() throws Exception {
CarAudioService service = setUpAudioService();
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_CONFIG_0, TEST_GAIN_INDEX);
callback.onAudioDeviceGainsChanged(List.of(Reasons.THERMAL_LIMITATION),
List.of(primaryAudioZoneCarGain, secondaryAudioZoneCarGain));
expectWithMessage("New audio gains for primary zone")
.that(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0)).isEqualTo(TEST_GAIN_INDEX);
expectWithMessage("New audio gains for secondary zone")
.that(service.getGroupVolume(TEST_REAR_LEFT_ZONE_ID,
TEST_PRIMARY_ZONE_GROUP_0)).isEqualTo(TEST_GAIN_INDEX);
}
@Test
public void onAudioPortsChanged_forMediaBus_changesVolumeRanges() throws Exception {
CarAudioService service = setUpAudioService();
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 =
service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0);
callback.onAudioPortsChanged(List.of(mediaBusDeviceInfo));
expectWithMessage("update audio port for media device")
.that(service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0)).isNotEqualTo(volumeGroupInfoBefore);
}
@Test
public void onAudioPortsChanged_forNavBus_changesVolumeRanges() throws Exception {
CarAudioService service = setUpAudioService();
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 =
service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_1);
callback.onAudioPortsChanged(List.of(navBusDeviceInfo));
expectWithMessage("update audio port for nav device")
.that(service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_1)).isNotEqualTo(volumeGroupInfoBefore);
}
@Test
public void onAudioPortsChanged_forMultipleBuses_changesVolumeRanges() throws Exception {
CarAudioService service = setUpAudioService();
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 =
service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0);
CarVolumeGroupInfo navVolumeGroupInfoBefore =
service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_1);
callback.onAudioPortsChanged(List.of(mediaBusDeviceInfo, navBusDeviceInfo));
expectWithMessage("update audio port for media device")
.that(service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0)).isNotEqualTo(mediaVolumeGroupInfoBefore);
expectWithMessage("update audio port for nav device")
.that(service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_1)).isNotEqualTo(navVolumeGroupInfoBefore);
}
@Test
public void getActiveAudioAttributesForZone() throws Exception {
CarAudioService service = setUpAudioService();
expectWithMessage("Default active audio attributes").that(
service.getActiveAudioAttributesForZone(PRIMARY_AUDIO_ZONE)).isEmpty();
}
@Test
public void getActiveAudioAttributesForZone_withActiveHalFocus() throws Exception {
when(mAudioManager.requestAudioFocus(any())).thenReturn(
AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
CarAudioService service = setUpAudioService();
requestHalAudioFocus(USAGE_ALARM);
expectWithMessage("HAL active audio attributes")
.that(service.getActiveAudioAttributesForZone(PRIMARY_AUDIO_ZONE))
.containsExactly(new AudioAttributes.Builder().setUsage(USAGE_ALARM).build());
}
@Test
public void getActiveAudioAttributesForZone_withActivePlayback() throws Exception {
CarAudioService service = setUpAudioService();
mockActivePlayback();
expectWithMessage("Playback active audio attributes")
.that(service.getActiveAudioAttributesForZone(PRIMARY_AUDIO_ZONE))
.containsExactly(new AudioAttributes.Builder().setUsage(USAGE_MEDIA).build());
}
@Test
public void getActiveAudioAttributesForZone_withActiveHalAndPlayback() throws Exception {
CarAudioService service = setUpAudioService();
mockActivePlayback();
when(mAudioManager.requestAudioFocus(any())).thenReturn(
AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
requestHalAudioFocus(USAGE_VOICE_COMMUNICATION);
expectWithMessage("Playback active audio attributes")
.that(service.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);
CarAudioService service = setUpAudioService();
when(mMockOccupantZoneService.getUserForOccupant(anyInt()))
.thenReturn(TEST_DRIVER_USER_ID, TEST_REAR_RIGHT_USER_ID);
assignOccupantToAudioZones();
expectWithMessage("Primary zone call state").that(
service.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);
CarAudioService service = setUpAudioService();
when(mMockOccupantZoneService.getUserForOccupant(anyInt()))
.thenReturn(TEST_REAR_LEFT_USER_ID, TEST_REAR_RIGHT_USER_ID);
assignOccupantToAudioZones();
expectWithMessage("Secondary zone call state").that(
service.getCallStateForZone(TEST_REAR_LEFT_ZONE_ID))
.isEqualTo(TelephonyManager.CALL_STATE_IDLE);
}
@Test
public void getVolumeGroupAndContextCount() throws Exception {
CarAudioService useCoreAudioCarAudioService =
setUpCarAudioServiceUsingCoreAudioRoutingAndVolume();
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() throws Exception {
CarAudioService service = setUpAudioService();
TestAudioZonesMirrorStatusCallbackCallback callback =
new TestAudioZonesMirrorStatusCallbackCallback(/* count= */ 1);
boolean registered = service.registerAudioZonesMirrorStatusCallback(callback);
expectWithMessage("Audio zones mirror status callback registered status")
.that(registered).isTrue();
}
@Test
public void registerAudioZonesMirrorStatusCallback_withoutMirroringEnabled() throws Exception {
CarAudioService service = setUpCarAudioServiceWithoutMirroring();
TestAudioZonesMirrorStatusCallbackCallback callback =
new TestAudioZonesMirrorStatusCallbackCallback(/* count= */ 1);
IllegalStateException thrown =
assertThrows(IllegalStateException.class, () ->
service.registerAudioZonesMirrorStatusCallback(callback));
expectWithMessage("Disabled audio zones mirror register exception").that(thrown)
.hasMessageThat().contains("Audio zones mirroring is required");
}
@Test
public void registerAudioZonesMirrorStatusCallback_withNullCallback() throws Exception {
CarAudioService service = setUpAudioService();
NullPointerException thrown =
assertThrows(NullPointerException.class, () ->
service.registerAudioZonesMirrorStatusCallback(/* callback= */ null));
expectWithMessage("Null audio zones mirror register exception").that(thrown)
.hasMessageThat().contains("Audio zones mirror status callback");
}
@Test
public void unregisterAudioZonesMirrorStatusCallback_withNullCallback() throws Exception {
CarAudioService service = setUpAudioService();
NullPointerException thrown =
assertThrows(NullPointerException.class, () -> service
.unregisterAudioZonesMirrorStatusCallback(/* callback= */ null));
expectWithMessage("Null audio zones mirror unregister exception").that(thrown)
.hasMessageThat().contains("Audio zones mirror status callback");
}
@Test
public void enableMirrorForAudioZones_withNullAudioZones() throws Exception {
CarAudioService service = setUpAudioService();
NullPointerException thrown =
assertThrows(NullPointerException.class, () ->
service.enableMirrorForAudioZones(/* audioZones= */ null));
expectWithMessage("Null mirror audio zones exception").that(thrown)
.hasMessageThat().contains("Mirror audio zones");
}
@Test
public void enableMirrorForAudioZones() throws Exception {
CarAudioService service = setUpAudioService();
TestAudioZonesMirrorStatusCallbackCallback callback =
getAudioZonesMirrorStatusCallback(service);
assignOccupantToAudioZones();
service.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_sendsMirrorInfoToAudioHAL() throws Exception {
CarAudioService service = setUpAudioService();
TestAudioZonesMirrorStatusCallbackCallback callback =
getAudioZonesMirrorStatusCallback(service);
assignOccupantToAudioZones();
service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
callback.waitForCallback();
String audioMirrorInfoCommand = captureAudioMirrorInfoCommand(1);
List<String> commands = Arrays.asList(audioMirrorInfoCommand.split(";"));
String sourceDeviceAddress = removeUpToEquals(commands.get(0));
expectWithMessage("Audio mirror source info").that(sourceDeviceAddress)
.isEqualTo(MIRROR_TEST_DEVICE);
String destinationsDevices = commands.get(1);
List<String> deviceAddresses = Arrays.asList(removeUpToEquals(destinationsDevices)
.split(","));
expectWithMessage("Audio mirror zone one info").that(deviceAddresses.get(0))
.isEqualTo(SECONDARY_TEST_DEVICE_CONFIG_0);
expectWithMessage("Audio mirror zone two info").that(deviceAddresses.get(1))
.isEqualTo(TERTIARY_TEST_DEVICE_1);
}
@Test
public void enableMirrorForAudioZones_forPrimaryZone_fails() throws Exception {
CarAudioService service = setUpAudioService();
assignOccupantToAudioZones();
int[] audioZones = new int[]{TEST_REAR_LEFT_ZONE_ID, PRIMARY_AUDIO_ZONE};
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () ->
service.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);
CarAudioService service = setUpAudioService();
getAudioZonesMirrorStatusCallback(service);
assignOccupantToAudioZones();
IllegalStateException thrown =
assertThrows(IllegalStateException.class, () ->
service.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 {
CarAudioService service = setUpAudioService();
assignOccupantToAudioZones();
int[] audioZones = new int[]{TEST_REAR_LEFT_ZONE_ID,
TEST_REAR_LEFT_ZONE_ID};
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () ->
service.enableMirrorForAudioZones(audioZones));
expectWithMessage("Repeated mirror audio zones exception").that(thrown)
.hasMessageThat().contains("must be unique");
}
@Test
public void enableMirrorForAudioZones_forAlreadyMirroredZones() throws Exception {
CarAudioService service = setUpAudioService();
TestAudioZonesMirrorStatusCallbackCallback callback =
getAudioZonesMirrorStatusCallback(service);
assignOccupantToAudioZones();
service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
callback.waitForCallback();
callback.reset(/* count= */ 1);
IllegalStateException thrown =
assertThrows(IllegalStateException.class, () ->
service.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 {
CarAudioService service = setUpAudioService();
TestPrimaryZoneMediaAudioRequestCallback
requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
assignOccupantToAudioZones();
long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
requestToken.waitForCallback();
requestToken.reset();
service.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allow= */ true);
requestToken.waitForCallback();
requestToken.reset();
IllegalStateException thrown =
assertThrows(IllegalStateException.class, () ->
service.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 {
CarAudioService service = setUpAudioService();
TestAudioZonesMirrorStatusCallbackCallback callback =
getAudioZonesMirrorStatusCallback(service);
assignOccupantToAudioZones();
service.enableMirrorForAudioZones(new int[] {TEST_REAR_RIGHT_ZONE_ID,
TEST_REAR_LEFT_ZONE_ID});
callback.waitForCallback();
callback.reset(/* count= */ 1);
IllegalStateException thrown =
assertThrows(IllegalStateException.class, () ->
service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES));
expectWithMessage("Audio mirror exception for inverted zone request")
.that(thrown).hasMessageThat().contains("is already mirroring");
}
@Test
public void enableMirrorForAudioZones_withNoMoreMirrorDevices_fails() throws Exception {
CarAudioService service = setUpAudioService();
TestAudioZonesMirrorStatusCallbackCallback callback =
getAudioZonesMirrorStatusCallback(service);
assignOccupantToAudioZones();
service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
callback.waitForCallback();
callback.reset(/* count= */ 1);
IllegalStateException thrown = assertThrows(IllegalStateException.class, () ->
service.enableMirrorForAudioZones(
new int[] {TEST_FRONT_ZONE_ID, TEST_REAR_ROW_3_ZONE_ID}));
expectWithMessage("Audio mirror for out of mirror devices exception")
.that(thrown).hasMessageThat().contains("available mirror output devices");
}
@Test
public void canEnableAudioMirror_withOutOfMirroringDevices() throws Exception {
CarAudioService service = setUpAudioService();
TestAudioZonesMirrorStatusCallbackCallback callback =
getAudioZonesMirrorStatusCallback(service);
assignOccupantToAudioZones();
service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
callback.waitForCallback();
expectWithMessage("Can audio mirror status").that(service
.canEnableAudioMirror())
.isEqualTo(AUDIO_MIRROR_OUT_OF_OUTPUT_DEVICES);
}
@Test
public void canEnableAudioMirror_withAudioMirrorEnabledAndNoPendingRequests() throws Exception {
CarAudioService service = setUpAudioService();
expectWithMessage("Can audio mirror status before audio mirror request")
.that(service.canEnableAudioMirror())
.isEqualTo(AUDIO_MIRROR_CAN_ENABLE);
}
@Test
public void canEnableAudioMirror_withMirroringDisabled() throws Exception {
CarAudioService service = setUpCarAudioServiceWithoutMirroring();
IllegalStateException thrown = assertThrows(IllegalStateException.class, () ->
service.canEnableAudioMirror());
expectWithMessage("Can enable audio mirror exception")
.that(thrown).hasMessageThat().contains("Audio zones mirroring is required");
}
@Test
public void extendAudioMirrorRequest() throws Exception {
CarAudioService service = setUpAudioService();
TestAudioZonesMirrorStatusCallbackCallback callback =
getAudioZonesMirrorStatusCallback(service);
assignOccupantToAudioZones();
long requestId = service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
callback.waitForCallback();
callback.reset(1);
service.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 {
CarAudioService service = setUpAudioService();
TestAudioZonesMirrorStatusCallbackCallback callback =
getAudioZonesMirrorStatusCallback(service);
assignOccupantToAudioZones();
long requestId = service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
callback.waitForCallback();
callback.reset(1);
NullPointerException thrown =
assertThrows(NullPointerException.class, () ->
service.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 {
CarAudioService service = setUpAudioService();
TestAudioZonesMirrorStatusCallbackCallback callback =
getAudioZonesMirrorStatusCallback(service);
assignOccupantToAudioZones();
long requestId = service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
callback.waitForCallback();
callback.reset(1);
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () ->
service.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() throws Exception {
CarAudioService service = setUpAudioService();
List<CarAudioZoneConfigInfo> zoneConfigInfos =
service.getAudioZoneConfigInfos(TEST_REAR_LEFT_ZONE_ID);
List<String> zoneConfigNames = zoneConfigInfos.stream().map(cf -> cf.getName()).toList();
expectWithMessage("Zone configurations for secondary zone").that(zoneConfigNames)
.containsExactly(SECONDARY_ZONE_CONFIG_NAME_1, SECONDARY_ZONE_CONFIG_NAME_2);
}
@Test
public void getCurrentAudioZoneConfigInfo() throws Exception {
CarAudioService service = setUpAudioService();
CarAudioZoneConfigInfo currentZoneConfigInfo =
service.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 {
CarAudioService service = setUpAudioService();
SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl();
assignOccupantToAudioZones();
CarAudioZoneConfigInfo zoneConfigSwitchTo = getZoneConfigToSwitch(service,
TEST_REAR_LEFT_ZONE_ID);
service.switchZoneToConfig(zoneConfigSwitchTo, callback);
callback.waitForCallback();
expectWithMessage("Updated zone configuration")
.that(callback.getZoneConfig())
.isEqualTo(getUpdatedCarAudioZoneConfigInfo(zoneConfigSwitchTo, service));
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);
CarAudioService service = setUpAudioService();
SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl();
assignOccupantToAudioZones();
CarAudioZoneConfigInfo zoneConfigSwitchTo = getZoneConfigToSwitch(service,
TEST_REAR_LEFT_ZONE_ID);
IllegalStateException thrown =
assertThrows(IllegalStateException.class, () ->
service.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 {
CarAudioService service = setUpAudioService();
SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl();
TestPrimaryZoneMediaAudioRequestCallback
requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
assignOccupantToAudioZones();
long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
TEST_REAR_LEFT_PASSENGER_OCCUPANT);
requestToken.waitForCallback();
requestToken.reset();
service.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allow= */ true);
requestToken.waitForCallback();
requestToken.reset();
CarAudioZoneConfigInfo zoneConfigSwitchTo = getZoneConfigToSwitch(service,
TEST_REAR_LEFT_ZONE_ID);
IllegalStateException thrown =
assertThrows(IllegalStateException.class, () ->
service.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 {
CarAudioService service = setUpAudioService();
SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl();
TestAudioZonesMirrorStatusCallbackCallback mirrorCallback =
getAudioZonesMirrorStatusCallback(service);
assignOccupantToAudioZones();
service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
mirrorCallback.waitForCallback();
mirrorCallback.reset(/* count= */ 1);
CarAudioZoneConfigInfo zoneConfigSwitchTo = getZoneConfigToSwitch(service,
TEST_REAR_LEFT_ZONE_ID);
IllegalStateException thrown =
assertThrows(IllegalStateException.class, () ->
service.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 {
CarAudioService service = setUpAudioService();
SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl();
assignOccupantToAudioZones();
AudioFocusInfo audioFocusInfo = createAudioFocusInfoForMedia(TEST_REAR_RIGHT_UID);
service.requestAudioFocusForTest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
CarAudioZoneConfigInfo zoneConfigSwitchTo = getZoneConfigToSwitch(service,
TEST_REAR_RIGHT_ZONE_ID);
service.switchZoneToConfig(zoneConfigSwitchTo, callback);
callback.waitForCallback();
expectWithMessage("Updated zone configuration with pending focus")
.that(callback.getZoneConfig())
.isEqualTo(getUpdatedCarAudioZoneConfigInfo(zoneConfigSwitchTo, service));
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 {
CarAudioService service = setUpAudioService();
SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl();
assignOccupantToAudioZones();
AudioFocusInfo audioFocusInfo = createAudioFocusInfoForMedia(TEST_REAR_RIGHT_UID);
service.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(service,
TEST_REAR_RIGHT_ZONE_ID);
service.switchZoneToConfig(zoneConfigSwitchTo, callback);
callback.waitForCallback();
expectWithMessage("Updated zone configuration with pending focus")
.that(callback.getZoneConfig())
.isEqualTo(getUpdatedCarAudioZoneConfigInfo(zoneConfigSwitchTo, service));
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 {
CarAudioService service = setUpAudioService();
SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl();
assignOccupantToAudioZones();
AudioFocusInfo audioFocusInfo = createAudioFocusInfoForMedia(TEST_REAR_RIGHT_UID);
service.requestAudioFocusForTest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
CarAudioZoneConfigInfo currentZoneConfig =
service.getCurrentAudioZoneConfigInfo(TEST_REAR_RIGHT_ZONE_ID);
service.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 switchZoneToConfig_withVolumeGroupEventCallbackRegistered_invokesEvent()
throws Exception {
CarAudioService service = setUpAudioService();
SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl();
CarVolumeEventCallbackImpl volumeEventCallback = new CarVolumeEventCallbackImpl();
assignOccupantToAudioZones();
CarAudioZoneConfigInfo zoneConfigSwitchTo = getZoneConfigToSwitch(service,
TEST_REAR_LEFT_ZONE_ID);
service.registerCarVolumeEventCallback(volumeEventCallback);
service.switchZoneToConfig(zoneConfigSwitchTo, callback);
callback.waitForCallback();
expectWithMessage("Updated zone configuration")
.that(callback.getZoneConfig())
.isEqualTo(getUpdatedCarAudioZoneConfigInfo(zoneConfigSwitchTo, service));
expectWithMessage("Zone configuration switching status")
.that(callback.getSwitchStatus()).isTrue();
volumeEventCallback.waitForCallback();
expectWithMessage("Volume events count after switching zone configuration")
.that(volumeEventCallback.getVolumeGroupEvents()).hasSize(1);
CarVolumeGroupEvent groupEvent = volumeEventCallback.getVolumeGroupEvents().get(0);
expectWithMessage("Volume event type after switching zone configuration")
.that(groupEvent.getEventTypes())
.isEqualTo(CarVolumeGroupEvent.EVENT_TYPE_ZONE_CONFIGURATION_CHANGED);
expectWithMessage("Volume group infos after switching zone configuration")
.that(groupEvent.getCarVolumeGroupInfos())
.containsExactly(mTestSecondaryZoneConfig1VolumeInfo0,
mTestSecondaryZoneConfig1VolumeInfo1);
}
@Test
public void switchZoneToConfig_updatesVolumeGroupInfos()
throws Exception {
CarAudioService service = setUpAudioService();
SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl();
assignOccupantToAudioZones();
Log.e(TAG, "Current volume group " + service.getVolumeGroupInfosForZone(
TEST_REAR_LEFT_ZONE_ID));
expectWithMessage("Volume group infos before switching zone configuration")
.that(service.getVolumeGroupInfosForZone(TEST_REAR_LEFT_ZONE_ID))
.containsExactly(mTestSecondaryConfig0VolumeGroup0Info);
CarAudioZoneConfigInfo zoneConfigSwitchTo = getZoneConfigToSwitch(service,
TEST_REAR_LEFT_ZONE_ID);
service.switchZoneToConfig(zoneConfigSwitchTo, callback);
callback.waitForCallback();
expectWithMessage("Volume group infos after switching zone configuration")
.that(service.getVolumeGroupInfosForZone(TEST_REAR_LEFT_ZONE_ID))
.containsExactly(mTestSecondaryZoneConfig1VolumeInfo0,
mTestSecondaryZoneConfig1VolumeInfo1);
}
@Test
public void switchZoneToConfig_withDynamicDevicesFlagEnabled() throws Exception {
mSetFlagsRule.enableFlags(Flags.FLAG_CAR_AUDIO_DYNAMIC_DEVICES);
CarAudioService service = setUpAudioService();
SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl();
assignOccupantToAudioZones();
CarAudioZoneConfigInfo previousConfig = service
.getCurrentAudioZoneConfigInfo(TEST_REAR_LEFT_ZONE_ID);
CarAudioZoneConfigInfo zoneConfigSwitchTo =
getZoneConfigToSwitch(service, TEST_REAR_LEFT_ZONE_ID);
service.switchZoneToConfig(zoneConfigSwitchTo, callback);
callback.waitForCallback();
expectWithMessage("Updated zone configuration, with dynamic devices enabled")
.that(callback.getZoneConfig().hasSameConfigInfo(zoneConfigSwitchTo)).isTrue();
expectWithMessage("Zone configuration switched status, with dynamic devices enabled")
.that(callback.getSwitchStatus()).isTrue();
CarAudioZoneConfigInfo switchedInfo = service
.getCurrentAudioZoneConfigInfo(TEST_REAR_LEFT_ZONE_ID);
expectWithMessage("Switched config active status")
.that(switchedInfo.isActive()).isTrue();
expectWithMessage("Switched config selected status")
.that(switchedInfo.isSelected()).isTrue();
CarAudioZoneConfigInfo previousUpdated =
getUpdatedCarAudioZoneConfigInfo(previousConfig, service);
expectWithMessage("Previous config active status")
.that(previousUpdated.isActive()).isTrue();
expectWithMessage("Previous config selected status")
.that(previousUpdated.isSelected()).isFalse();
}
@Test
public void registerAudioZoneConfigsChangeCallback() throws Exception {
IAudioZoneConfigurationsChangeCallback callback =
new TestAudioZoneConfigurationsChangeCallback();
CarAudioService service = setUpAudioService();
boolean registered = service.registerAudioZoneConfigsChangeCallback(callback);
expectWithMessage("Car audio zone configuration change register status")
.that(registered).isTrue();
}
@Test
public void registerAudioZoneConfigsChangeCallback_multipleTimes() throws Exception {
IAudioZoneConfigurationsChangeCallback callback =
new TestAudioZoneConfigurationsChangeCallback();
CarAudioService service = setUpAudioService();
service.registerAudioZoneConfigsChangeCallback(callback);
boolean registered = service.registerAudioZoneConfigsChangeCallback(callback);
expectWithMessage("Car audio zone configuration change re-register status")
.that(registered).isTrue();
}
@Test
public void registerAudioZoneConfigsChangeCallback_withNullCallback() throws Exception {
CarAudioService service = setUpAudioService();
NullPointerException thrown = assertThrows(NullPointerException.class,
() -> service.registerAudioZoneConfigsChangeCallback(null));
expectWithMessage("Car audio zone configuration change registration exception")
.that(thrown).hasMessageThat().contains("Car audio zone configs");
}
@Test
public void onAudioDevicesAdded_forDynamicDevicesEnabled() throws Exception {
CarAudioService audioServiceWithDynamicDevices = setUpAudioServiceWithDynamicDevices();
audioServiceWithDynamicDevices.init();
TestAudioZoneConfigurationsChangeCallback
configCallback = getRegisteredZoneConfigCallback(audioServiceWithDynamicDevices);
AudioDeviceCallback deviceCallback = captureAudioDeviceCallback();
deviceCallback.onAudioDevicesAdded(new AudioDeviceInfo[]{mBTAudioDeviceInfo});
configCallback.waitForCallback();
List<CarAudioZoneConfigInfo> zoneConfigInfos =
audioServiceWithDynamicDevices.getAudioZoneConfigInfos(PRIMARY_AUDIO_ZONE);
CarAudioZoneConfigInfo btConfig = zoneConfigInfos.stream()
.filter(config -> config.getName().equals(SECONDARY_CONFIG_NAME_DYNAMIC_DEVICES))
.findFirst().orElseThrow();
expectWithMessage("Enabled bluetooth configuration").that(btConfig.isActive()).isTrue();
}
@Test
public void onAudioDevicesAdded_forDynamicDevicesEnabled_triggersCallback() throws Exception {
CarAudioService serviceWithDynamicDevices = setUpAudioServiceWithDynamicDevices();
serviceWithDynamicDevices.init();
TestAudioZoneConfigurationsChangeCallback
configCallback = getRegisteredZoneConfigCallback(serviceWithDynamicDevices);
AudioDeviceCallback deviceCallback = captureAudioDeviceCallback();
deviceCallback.onAudioDevicesAdded(new AudioDeviceInfo[]{mBTAudioDeviceInfo});
configCallback.waitForCallback();
expectWithMessage("Enabled dynamic config callback status").that(configCallback.mStatus)
.isEqualTo(CONFIG_STATUS_CHANGED);
CarAudioZoneConfigInfo btConfig = configCallback.mInfos.stream()
.filter(config -> config.getName().equals(SECONDARY_CONFIG_NAME_DYNAMIC_DEVICES))
.findFirst().orElseThrow();
expectWithMessage("Callback enabled bluetooth configuration").that(btConfig.isActive())
.isTrue();
}
@Test
public void onAudioDevicesRemoved_forDynamicDevicesEnabled_triggersCallback()
throws Exception {
CarAudioService serviceWithDynamicDevices = setUpAudioServiceWithDynamicDevices();
serviceWithDynamicDevices.init();
AudioDeviceCallback deviceCallback = captureAudioDeviceCallback();
TestAudioZoneConfigurationsChangeCallback
configCallback = getRegisteredZoneConfigCallback(serviceWithDynamicDevices);
deviceCallback.onAudioDevicesAdded(new AudioDeviceInfo[]{mBTAudioDeviceInfo});
configCallback.waitForCallback();
configCallback.reset();
deviceCallback.onAudioDevicesRemoved(new AudioDeviceInfo[]{mBTAudioDeviceInfo});
configCallback.waitForCallback();
expectWithMessage("Disabled dynamic config callback status").that(configCallback.mStatus)
.isEqualTo(CONFIG_STATUS_CHANGED);
CarAudioZoneConfigInfo btConfig = configCallback.mInfos.stream()
.filter(config -> config.getName().equals(SECONDARY_CONFIG_NAME_DYNAMIC_DEVICES))
.findFirst().orElseThrow();
expectWithMessage("Callback disabled bluetooth configuration").that(btConfig.isActive())
.isFalse();
}
@Test
public void onAudioDevicesRemoved_afterAdded_forDynamicDevicesEnabled() throws Exception {
CarAudioService audioServiceWithDynamicDevices = setUpAudioServiceWithDynamicDevices();
audioServiceWithDynamicDevices.init();
TestAudioZoneConfigurationsChangeCallback
configCallback = getRegisteredZoneConfigCallback(audioServiceWithDynamicDevices);
AudioDeviceCallback deviceCallback = captureAudioDeviceCallback();
deviceCallback.onAudioDevicesAdded(new AudioDeviceInfo[]{mBTAudioDeviceInfo});
configCallback.waitForCallback();
configCallback.reset();
deviceCallback.onAudioDevicesRemoved(new AudioDeviceInfo[]{mBTAudioDeviceInfo});
configCallback.waitForCallback();
List<CarAudioZoneConfigInfo> zoneConfigInfos =
audioServiceWithDynamicDevices.getAudioZoneConfigInfos(PRIMARY_AUDIO_ZONE);
CarAudioZoneConfigInfo btConfig = zoneConfigInfos.stream()
.filter(config -> config.getName().equals(SECONDARY_CONFIG_NAME_DYNAMIC_DEVICES))
.findFirst().orElseThrow();
expectWithMessage("Enabled bluetooth configuration after removed device")
.that(btConfig.isActive()).isFalse();
}
@Test
public void onAudioDevicesRemoved_forSelectedDynamicDevicesEnabled_triggersCallback()
throws Exception {
SwitchAudioZoneConfigCallbackImpl switchCallback = new SwitchAudioZoneConfigCallbackImpl();
CarAudioService serviceWithDynamicDevices = setUpAudioServiceWithDynamicDevices();
serviceWithDynamicDevices.init();
assignOccupantToAudioZones();
AudioDeviceCallback deviceCallback = captureAudioDeviceCallback();
TestAudioZoneConfigurationsChangeCallback
configCallback = getRegisteredZoneConfigCallback(serviceWithDynamicDevices);
deviceCallback.onAudioDevicesAdded(new AudioDeviceInfo[]{mBTAudioDeviceInfo});
configCallback.waitForCallback();
configCallback.reset();
List<CarAudioZoneConfigInfo> infos =
serviceWithDynamicDevices.getAudioZoneConfigInfos(PRIMARY_AUDIO_ZONE);
CarAudioZoneConfigInfo btConfig = infos.stream().filter(
config -> config.getName().equals(SECONDARY_CONFIG_NAME_DYNAMIC_DEVICES))
.findFirst().orElseThrow();
serviceWithDynamicDevices.switchZoneToConfig(btConfig, switchCallback);
switchCallback.waitForCallback();
deviceCallback.onAudioDevicesRemoved(new AudioDeviceInfo[]{mBTAudioDeviceInfo});
configCallback.waitForCallback();
CarAudioZoneConfigInfo updatedBTConfig = configCallback.mInfos.stream().filter(
config -> config.getName().equals(SECONDARY_CONFIG_NAME_DYNAMIC_DEVICES))
.findFirst().orElseThrow();
expectWithMessage("Disabled selected dynamic config callback status")
.that(configCallback.mStatus).isEqualTo(CONFIG_STATUS_AUTO_SWITCHED);
expectWithMessage("Callback disabled selected bluetooth configuration")
.that(updatedBTConfig.isActive()).isFalse();
}
@Test
public void unregisterAudioZoneConfigsChangeCallback() throws Exception {
IAudioZoneConfigurationsChangeCallback callback =
new TestAudioZoneConfigurationsChangeCallback();
CarAudioService service = setUpAudioService();
service.registerAudioZoneConfigsChangeCallback(callback);
boolean registered = service.unregisterAudioZoneConfigsChangeCallback(callback);
expectWithMessage("Car audio zone configuration change un-register status")
.that(registered).isTrue();
}
@Test
public void unregisterAudioZoneConfigsChangeCallback_afterUnregister_fails() throws Exception {
IAudioZoneConfigurationsChangeCallback callback =
new TestAudioZoneConfigurationsChangeCallback();
CarAudioService service = setUpAudioService();
service.registerAudioZoneConfigsChangeCallback(callback);
service.unregisterAudioZoneConfigsChangeCallback(callback);
boolean registered = service.unregisterAudioZoneConfigsChangeCallback(callback);
expectWithMessage("Car audio zone configuration change un-register multiple times status")
.that(registered).isFalse();
}
@Test
public void unregisterAudioZoneConfigsChangeCallback_withNullCallback() throws Exception {
CarAudioService service = setUpAudioService();
NullPointerException thrown = assertThrows(NullPointerException.class,
() -> service.unregisterAudioZoneConfigsChangeCallback(null));
expectWithMessage("Car audio zone configuration change un-registration exception")
.that(thrown).hasMessageThat().contains("Car audio zone configs");
}
@Test
public void disableAudioMirrorForZone_withInvalidZone() throws Exception {
CarAudioService service = setUpAudioService();
assignOccupantToAudioZones();
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () ->
service.disableAudioMirrorForZone(INVALID_AUDIO_ZONE));
expectWithMessage("Disable mirror for invalid audio zone exception").that(thrown)
.hasMessageThat().contains("Invalid audio zone");
}
@Test
public void disableAudioMirrorForZone_withMirroringDisabled() throws Exception {
CarAudioService service = setUpCarAudioServiceWithoutMirroring();
IllegalStateException thrown =
assertThrows(IllegalStateException.class, () ->
service.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 {
CarAudioService service = setUpAudioService();
TestAudioZonesMirrorStatusCallbackCallback callback =
getAudioZonesMirrorStatusCallback(service);
assignOccupantToAudioZones();
service.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 {
CarAudioService service = setUpAudioService();
TestAudioZonesMirrorStatusCallbackCallback callback =
getAudioZonesMirrorStatusCallback(service);
assignOccupantToAudioZones();
service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
callback.waitForCallback();
callback.reset(/* count= */ 1);
service.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 {
CarAudioService service = setUpAudioService();
TestAudioZonesMirrorStatusCallbackCallback callback =
getAudioZonesMirrorStatusCallback(service);
assignOccupantToAudioZones();
service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
callback.waitForCallback();
callback.reset(/* count= */ 1);
service.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);
String audioMirrorOffCommand = captureAudioMirrorInfoCommand(2);
expectWithMessage("Audio HAL off source for mirroring zone")
.that(audioMirrorOffCommand).contains(MIRROR_TEST_DEVICE);
expectWithMessage("Audio HAL off signal for mirroring zone")
.that(audioMirrorOffCommand).contains(MIRROR_OFF_SIGNAL);
}
@Test
public void disableAudioMirrorForZone_withPendingFocus()
throws Exception {
CarAudioService service = setUpAudioService();
TestAudioZonesMirrorStatusCallbackCallback callback =
getAudioZonesMirrorStatusCallback(service);
assignOccupantToAudioZones();
service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
callback.waitForCallback();
callback.reset(/* count= */ 2);
AudioFocusInfo audioFocusInfo = createAudioFocusInfoForMedia(TEST_REAR_RIGHT_UID);
service.requestAudioFocusForTest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
service.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() throws Exception {
CarAudioService service = setUpCarAudioServiceWithoutMirroring();
IllegalStateException thrown =
assertThrows(IllegalStateException.class, () ->
service.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() throws Exception {
CarAudioService service = setUpAudioService();
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () ->
service.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 {
CarAudioService service = setUpAudioService();
TestAudioZonesMirrorStatusCallbackCallback callback =
getAudioZonesMirrorStatusCallback(service);
assignOccupantToAudioZones();
long requestId = service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
callback.waitForCallback();
callback.reset(1);
service.disableAudioMirror(requestId);
callback.waitForCallback();
callback.reset(1);
service.disableAudioMirror(requestId);
expectWithMessage("Disable audio mirror for non-mirroring zone callback count")
.that(callback.mNumberOfCalls).isEqualTo(2);
}
@Test
public void disableAudioMirror_forMirroringZones() throws Exception {
CarAudioService service = setUpAudioService();
TestAudioZonesMirrorStatusCallbackCallback callback =
getAudioZonesMirrorStatusCallback(service);
assignOccupantToAudioZones();
long requestId = service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
callback.waitForCallback();
callback.reset(/* count= */ 1);
service.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);
String audioMirrorOffCommand = captureAudioMirrorInfoCommand(2);
expectWithMessage("Audio HAL off source for mirroring zones")
.that(audioMirrorOffCommand).contains(MIRROR_TEST_DEVICE);
expectWithMessage("Audio HAL off signal for mirroring zones")
.that(audioMirrorOffCommand).contains(MIRROR_OFF_SIGNAL);
}
@Test
public void disableAudioMirror_withPendingFocus() throws Exception {
CarAudioService service = setUpAudioService();
TestAudioZonesMirrorStatusCallbackCallback callback =
getAudioZonesMirrorStatusCallback(service);
assignOccupantToAudioZones();
long requestId = service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
callback.waitForCallback();
callback.reset(/* count= */ 2);
AudioFocusInfo audioFocusInfo = createAudioFocusInfoForMedia(TEST_REAR_RIGHT_UID);
service.requestAudioFocusForTest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
service.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);
}
@Test
public void getMirrorAudioZonesForAudioZone_withoutMirroringEnabled()
throws Exception {
CarAudioService service = setUpAudioService();
assignOccupantToAudioZones();
int[] zones = service.getMirrorAudioZonesForAudioZone(TEST_REAR_RIGHT_ZONE_ID);
expectWithMessage("Mirroring zones for non mirror zone %s", TEST_REAR_RIGHT_ZONE_ID)
.that(zones).asList().isEmpty();
}
@Test
public void getMirrorAudioZonesForAudioZone_withMirroringEnabled() throws Exception {
CarAudioService service = setUpAudioService();
TestAudioZonesMirrorStatusCallbackCallback callback =
getAudioZonesMirrorStatusCallback(service);
assignOccupantToAudioZones();
service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
callback.waitForCallback();
int[] zones = service.getMirrorAudioZonesForAudioZone(TEST_REAR_RIGHT_ZONE_ID);
expectWithMessage("Mirroring zones for mirror zone %s", TEST_REAR_RIGHT_ZONE_ID).that(zones)
.asList().containsExactly(TEST_REAR_LEFT_ZONE_ID, TEST_REAR_RIGHT_ZONE_ID);
}
@Test
public void getMirrorAudioZonesForAudioZone_afterDisableMirror() throws Exception {
CarAudioService service = setUpAudioService();
TestAudioZonesMirrorStatusCallbackCallback callback =
getAudioZonesMirrorStatusCallback(service);
assignOccupantToAudioZones();
long requestId = service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
callback.waitForCallback();
callback.reset(1);
service.disableAudioMirror(requestId);
callback.waitForCallback();
int[] zones = service.getMirrorAudioZonesForAudioZone(TEST_REAR_RIGHT_ZONE_ID);
expectWithMessage("Mirroring zones for mirror zone %s after disabling mirroring",
TEST_REAR_RIGHT_ZONE_ID).that(zones).asList().isEmpty();
}
@Test
public void getMirrorAudioZonesForAudioZone_afterPassengerLogout() throws Exception {
CarAudioService service = setUpAudioService();
TestAudioZonesMirrorStatusCallbackCallback callback =
getAudioZonesMirrorStatusCallback(service);
assignOccupantToAudioZones();
service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
callback.waitForCallback();
callback.reset(1);
simulateLogoutRightPassengers();
callback.waitForCallback();
int[] zones = service.getMirrorAudioZonesForAudioZone(TEST_REAR_RIGHT_ZONE_ID);
expectWithMessage("Mirroring zones for mirror zone %s after logout",
TEST_REAR_RIGHT_ZONE_ID).that(zones).asList().isEmpty();
}
@Test
public void getMirrorAudioZonesForMirrorRequest_withMirroringEnabled() throws Exception {
CarAudioService service = setUpAudioService();
TestAudioZonesMirrorStatusCallbackCallback callback =
getAudioZonesMirrorStatusCallback(service);
assignOccupantToAudioZones();
long requestId = service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
callback.waitForCallback();
int[] zones = service.getMirrorAudioZonesForMirrorRequest(requestId);
expectWithMessage("Mirroring zones for mirror request %s", requestId).that(zones).asList()
.containsExactly(TEST_REAR_LEFT_ZONE_ID, TEST_REAR_RIGHT_ZONE_ID);
}
@Test
public void getMirrorAudioZonesForMirrorRequest_afterDisableMirror() throws Exception {
CarAudioService service = setUpAudioService();
TestAudioZonesMirrorStatusCallbackCallback callback =
getAudioZonesMirrorStatusCallback(service);
assignOccupantToAudioZones();
long requestId = service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
callback.waitForCallback();
callback.reset(1);
service.disableAudioMirror(requestId);
callback.waitForCallback();
int[] zones = service.getMirrorAudioZonesForMirrorRequest(TEST_REAR_RIGHT_ZONE_ID);
expectWithMessage("Mirroring zones for mirror request %s after disabling mirroring",
requestId).that(zones).asList().isEmpty();
}
@Test
public void getMirrorAudioZonesForMirrorRequest_afterPassengerLogout() throws Exception {
CarAudioService service = setUpAudioService();
TestAudioZonesMirrorStatusCallbackCallback callback =
getAudioZonesMirrorStatusCallback(service);
assignOccupantToAudioZones();
long requestId = service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
callback.waitForCallback();
callback.reset(1);
simulateLogoutRightPassengers();
callback.waitForCallback();
int[] zones = service.getMirrorAudioZonesForMirrorRequest(requestId);
expectWithMessage("Mirroring zones for mirror request %s after logout",
TEST_REAR_RIGHT_ZONE_ID).that(zones).asList().isEmpty();
}
@Test
public void onAudioVolumeGroupChanged_dispatchCallbackEvent() throws Exception {
CarAudioService useCoreAudioCarAudioService =
setUpCarAudioServiceUsingCoreAudioRoutingAndVolume();
int musicIndex = useCoreAudioCarAudioService.getGroupVolume(
PRIMARY_AUDIO_ZONE, CoreAudioRoutingUtils.MUSIC_CAR_GROUP_ID);
// Report a volume change
when(mAudioManager.getVolumeIndexForAttributes(eq(CoreAudioRoutingUtils.MUSIC_ATTRIBUTES)))
.thenReturn(musicIndex + 1);
when(mAudioManager.getLastAudibleVolumeForVolumeGroup(CoreAudioRoutingUtils.MUSIC_GROUP_ID))
.thenReturn(musicIndex + 1);
when(mAudioManager.isVolumeGroupMuted(CoreAudioRoutingUtils.MUSIC_GROUP_ID))
.thenReturn(false);
useCoreAudioCarAudioService.onAudioVolumeGroupChanged(PRIMARY_AUDIO_ZONE,
CoreAudioRoutingUtils.MUSIC_GROUP_NAME, /* flags= */ 0);
verify(mCarVolumeCallbackHandler)
.onVolumeGroupChange(PRIMARY_AUDIO_ZONE, CoreAudioRoutingUtils.MUSIC_CAR_GROUP_ID,
FLAG_SHOW_UI | FLAG_PLAY_SOUND);
}
@Test
public void onAudioVolumeGroupChanged_noDispatchCallbackEvent_whenAlreadySynced()
throws Exception {
CarAudioService useCoreAudioCarAudioService =
setUpCarAudioServiceUsingCoreAudioRoutingAndVolume();
useCoreAudioCarAudioService.setGroupVolume(PRIMARY_AUDIO_ZONE,
CoreAudioRoutingUtils.MUSIC_CAR_GROUP_ID, CoreAudioRoutingUtils.MUSIC_AM_INIT_INDEX,
/* flags= */ 0);
reset(mCarVolumeCallbackHandler);
useCoreAudioCarAudioService.onAudioVolumeGroupChanged(PRIMARY_AUDIO_ZONE,
CoreAudioRoutingUtils.MUSIC_GROUP_NAME, /* flags= */ 0);
verify(mCarVolumeCallbackHandler, never())
.onVolumeGroupChange(anyInt(), anyInt(), anyInt());
}
@Test
public void onAudioVolumeGroupChanged_dispatchCallbackEvent_whenMuted() throws Exception {
CarAudioService useCoreAudioCarAudioService =
setUpCarAudioServiceUsingCoreAudioRoutingAndVolume();
// Report a mute change
when(mAudioManager.getVolumeIndexForAttributes(eq(CoreAudioRoutingUtils.MUSIC_ATTRIBUTES)))
.thenReturn(CoreAudioRoutingUtils.MUSIC_MIN_INDEX);
when(mAudioManager.isVolumeGroupMuted(CoreAudioRoutingUtils.MUSIC_GROUP_ID))
.thenReturn(true);
useCoreAudioCarAudioService.onAudioVolumeGroupChanged(PRIMARY_AUDIO_ZONE,
CoreAudioRoutingUtils.MUSIC_GROUP_NAME, /* flags= */ 0);
verify(mCarVolumeCallbackHandler).onGroupMuteChange(PRIMARY_AUDIO_ZONE,
CoreAudioRoutingUtils.MUSIC_CAR_GROUP_ID, FLAG_SHOW_UI);
}
@Test
public void onVolumeGroupEvent_withVolumeEvent_triggersCallback() throws Exception {
CarAudioService service = setUpAudioService();
CarVolumeEventCallbackImpl volumeEventCallback = new CarVolumeEventCallbackImpl();
service.registerCarVolumeEventCallback(volumeEventCallback);
service.onVolumeGroupEvent(List.of(mTestCarVolumeGroupEvent));
expectWithMessage("Volume event callback reception status")
.that(volumeEventCallback.waitForCallback()).isTrue();
verify(mCarVolumeCallbackHandler, never()).onGroupMuteChange(anyInt(), anyInt(), anyInt());
verify(mCarVolumeCallbackHandler)
.onVolumeGroupChange(PRIMARY_AUDIO_ZONE, CoreAudioRoutingUtils.MUSIC_CAR_GROUP_ID,
/* flags= */ 0);
expectWithMessage("Volume events count after volume event")
.that(volumeEventCallback.getVolumeGroupEvents()).hasSize(1);
CarVolumeGroupEvent groupEvent = volumeEventCallback.getVolumeGroupEvents().get(0);
expectWithMessage("Volume event type after volume event")
.that(groupEvent.getEventTypes())
.isEqualTo(CarVolumeGroupEvent.EVENT_TYPE_VOLUME_GAIN_INDEX_CHANGED);
expectWithMessage("Volume group infos after unmute")
.that(groupEvent.getCarVolumeGroupInfos())
.containsExactly(mTestPrimaryZoneUmMutedVolueInfo0);
}
@Test
public void onVolumeGroupEvent_withMuteEvent_triggersCallback() throws Exception {
CarAudioService service = setUpAudioService();
CarVolumeEventCallbackImpl volumeEventCallback = new CarVolumeEventCallbackImpl();
service.registerCarVolumeEventCallback(volumeEventCallback);
service.onVolumeGroupEvent(List.of(mTestCarMuteGroupEvent));
expectWithMessage("Volume event callback reception status")
.that(volumeEventCallback.waitForCallback()).isTrue();
verify(mCarVolumeCallbackHandler, never())
.onVolumeGroupChange(anyInt(), anyInt(), anyInt());
verify(mCarVolumeCallbackHandler)
.onGroupMuteChange(PRIMARY_AUDIO_ZONE, CoreAudioRoutingUtils.MUSIC_CAR_GROUP_ID,
/* flags= */ 0);
expectWithMessage("Volume events count after mute event")
.that(volumeEventCallback.getVolumeGroupEvents()).hasSize(1);
CarVolumeGroupEvent groupEvent = volumeEventCallback.getVolumeGroupEvents().get(0);
expectWithMessage("Volume event type after mute event")
.that(groupEvent.getEventTypes())
.isEqualTo(CarVolumeGroupEvent.EVENT_TYPE_MUTE_CHANGED);
expectWithMessage("Volume group infos after mute event")
.that(groupEvent.getCarVolumeGroupInfos())
.containsExactly(mTestPrimaryZoneUmMutedVolueInfo0);
}
@Test
public void onVolumeGroupEvent_withoutMuteOrVolumeEvent_doesNotTriggerCallback()
throws Exception {
CarAudioService service = setUpAudioService();
CarVolumeEventCallbackImpl volumeEventCallback = new CarVolumeEventCallbackImpl();
service.registerCarVolumeEventCallback(volumeEventCallback);
service.onVolumeGroupEvent(List.of(mTestCarZoneReconfigurationEvent));
expectWithMessage("Volume event callback reception status")
.that(volumeEventCallback.waitForCallback()).isTrue();
verify(mCarVolumeCallbackHandler, never())
.onVolumeGroupChange(anyInt(), anyInt(), anyInt());
verify(mCarVolumeCallbackHandler, never()).onGroupMuteChange(anyInt(), anyInt(), anyInt());
expectWithMessage("Volume events count after reconfiguration event")
.that(volumeEventCallback.getVolumeGroupEvents()).hasSize(1);
CarVolumeGroupEvent groupEvent = volumeEventCallback.getVolumeGroupEvents().get(0);
expectWithMessage("Volume event type after reconfiguration event")
.that(groupEvent.getEventTypes())
.isEqualTo(CarVolumeGroupEvent.EVENT_TYPE_ZONE_CONFIGURATION_CHANGED);
expectWithMessage("Volume group infos after reconfiguration event")
.that(groupEvent.getCarVolumeGroupInfos())
.containsExactly(mTestPrimaryZoneUmMutedVolueInfo0);
}
@Test
public void setMuted_whenUnmuted_onActivation_triggersCallback() throws Exception {
CarAudioService service = setUpAudioService();
CarVolumeEventCallbackImpl volumeEventCallback = new CarVolumeEventCallbackImpl();
service.registerCarVolumeEventCallback(volumeEventCallback);
service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
/* mute= */ true, TEST_FLAGS);
verify(mCarVolumeCallbackHandler).onGroupMuteChange(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0, TEST_FLAGS);
expectWithMessage("Volume event callback reception status after mute")
.that(volumeEventCallback.waitForCallback()).isTrue();
expectWithMessage("Volume events count after mute")
.that(volumeEventCallback.getVolumeGroupEvents()).hasSize(1);
CarVolumeGroupEvent groupEvent = volumeEventCallback.getVolumeGroupEvents().get(0);
expectWithMessage("Volume event type after mute")
.that(groupEvent.getEventTypes())
.isEqualTo(CarVolumeGroupEvent.EVENT_TYPE_MUTE_CHANGED);
expectWithMessage("Volume group infos after mute")
.that(groupEvent.getCarVolumeGroupInfos())
.containsExactly(mTestPrimaryZoneVolumeInfo0);
}
@Test
public void setMuted_whenUnmuted_onDeactivation_doesNotTriggerCallback() throws Exception {
CarAudioService service = setUpAudioService();
CarVolumeEventCallbackImpl volumeEventCallback = new CarVolumeEventCallbackImpl();
service.registerCarVolumeEventCallback(volumeEventCallback);
service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
/* mute= */ false, TEST_FLAGS);
verify(mCarVolumeCallbackHandler, never()).onGroupMuteChange(anyInt(), anyInt(), anyInt());
expectWithMessage("Volume event callback reception status")
.that(volumeEventCallback.waitForCallback()).isFalse();
}
@Test
public void setMuted_whenMuted_onDeactivation_triggersCallback() throws Exception {
CarAudioService service = setUpAudioService();
CarVolumeEventCallbackImpl volumeEventCallback = new CarVolumeEventCallbackImpl();
service.registerCarVolumeEventCallback(volumeEventCallback);
service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
/* mute= */ true, TEST_FLAGS);
volumeEventCallback.waitForCallback();
volumeEventCallback.reset();
reset(mCarVolumeCallbackHandler);
service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
/* mute= */ false, TEST_FLAGS);
verify(mCarVolumeCallbackHandler).onGroupMuteChange(PRIMARY_AUDIO_ZONE,
TEST_PRIMARY_ZONE_GROUP_0, TEST_FLAGS);
expectWithMessage("Volume event callback reception status after unmute")
.that(volumeEventCallback.waitForCallback()).isTrue();
expectWithMessage("Volume events count after mute")
.that(volumeEventCallback.getVolumeGroupEvents()).hasSize(1);
CarVolumeGroupEvent groupEvent = volumeEventCallback.getVolumeGroupEvents().get(0);
expectWithMessage("Volume event type after unmute")
.that(groupEvent.getEventTypes())
.isEqualTo(CarVolumeGroupEvent.EVENT_TYPE_MUTE_CHANGED);
expectWithMessage("Volume group infos after unmute")
.that(groupEvent.getCarVolumeGroupInfos())
.containsExactly(mTestPrimaryZoneUmMutedVolueInfo0);
}
@Test
public void setMuted_whenMuted_onActivation_doesNotTriggerCallback() throws Exception {
CarAudioService service = setUpAudioService();
CarVolumeEventCallbackImpl volumeEventCallback = new CarVolumeEventCallbackImpl();
service.registerCarVolumeEventCallback(volumeEventCallback);
service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
/* mute= */ true, TEST_FLAGS);
volumeEventCallback.waitForCallback();
volumeEventCallback.reset();
reset(mCarVolumeCallbackHandler);
service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
/* mute= */ true, TEST_FLAGS);
verify(mCarVolumeCallbackHandler, never()).onGroupMuteChange(anyInt(), anyInt(), anyInt());
expectWithMessage("Volume event callback reception status")
.that(volumeEventCallback.waitForCallback()).isFalse();
}
private CarAudioService setUpCarAudioServiceWithoutZoneMapping() throws Exception {
setUpTempFileForAudioConfiguration(R.raw.car_audio_configuration_without_zone_mapping);
when(mMockAudioService.setUidDeviceAffinity(any(), anyInt(), any(), any()))
.thenReturn(SUCCESS);
CarAudioService noZoneMappingAudioService = new CarAudioService(mMockContext,
mTempCarAudioConfigFile.getFile().getAbsolutePath(), mCarVolumeCallbackHandler);
noZoneMappingAudioService.init();
return noZoneMappingAudioService;
}
private CarAudioService setUpAudioService() throws Exception {
setUpTempFileForAudioConfiguration(R.raw.car_audio_configuration);
CarAudioService service = new CarAudioService(mMockContext,
mTempCarAudioConfigFile.getFile().getAbsolutePath(), mCarVolumeCallbackHandler);
service.init();
return service;
}
private CarAudioService setUpAudioServiceWithoutInit() throws Exception {
setUpTempFileForAudioConfiguration(R.raw.car_audio_configuration);
CarAudioService service = new CarAudioService(mMockContext,
mTempCarAudioConfigFile.getFile().getAbsolutePath(), mCarVolumeCallbackHandler);
return service;
}
private CarAudioService setUpAudioServiceWithoutDynamicRouting() throws Exception {
setUpTempFileForAudioConfiguration(R.raw.car_audio_configuration);
when(mMockResources.getBoolean(audioUseDynamicRouting)).thenReturn(false);
CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext,
mTempCarAudioConfigFile.getFile().getAbsolutePath(), mCarVolumeCallbackHandler);
nonDynamicAudioService.init();
return nonDynamicAudioService;
}
private CarAudioService setUpAudioServiceWithDisabledResource(int resource) throws Exception {
setUpTempFileForAudioConfiguration(R.raw.car_audio_configuration);
when(mMockResources.getBoolean(resource)).thenReturn(false);
CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext,
mTempCarAudioConfigFile.getFile().getAbsolutePath(), mCarVolumeCallbackHandler);
nonDynamicAudioService.init();
return nonDynamicAudioService;
}
private static TestAudioZoneConfigurationsChangeCallback getRegisteredZoneConfigCallback(
CarAudioService audioServiceWithDynamicDevices) {
TestAudioZoneConfigurationsChangeCallback configCallback =
new TestAudioZoneConfigurationsChangeCallback();
audioServiceWithDynamicDevices.registerAudioZoneConfigsChangeCallback(configCallback);
return configCallback;
}
private AudioDeviceCallback captureAudioDeviceCallback() {
ArgumentCaptor<AudioDeviceCallback> captor =
ArgumentCaptor.forClass(AudioDeviceCallback.class);
verify(mAudioManager).registerAudioDeviceCallback(captor.capture(), any());
return captor.getValue();
}
private CarAudioService setUpAudioServiceWithDynamicDevices() throws Exception {
setUpTempFileForAudioConfiguration(R.raw.car_audio_configuration_using_dynamic_routing);
return setUpAudioServiceWithDynamicDevices(mTempCarAudioConfigFile);
}
private CarAudioService setUpAudioServiceWithDynamicDevices(TemporaryFile file) {
mSetFlagsRule.enableFlags(Flags.FLAG_CAR_AUDIO_DYNAMIC_DEVICES);
when(mMockResources.getBoolean(audioUseCoreVolume)).thenReturn(true);
when(mMockResources.getBoolean(audioUseCoreRouting)).thenReturn(false);
CarAudioService audioServiceWithDynamicDevices = new CarAudioService(mMockContext,
file.getFile().getAbsolutePath(), mCarVolumeCallbackHandler);
return audioServiceWithDynamicDevices;
}
private CarAudioZoneConfigInfo getUpdatedCarAudioZoneConfigInfo(
CarAudioZoneConfigInfo previousConfig, CarAudioService service) {
List<CarAudioZoneConfigInfo> infos =
service.getAudioZoneConfigInfos(previousConfig.getZoneId());
CarAudioZoneConfigInfo previousUpdated = infos.stream()
.filter(i-> i.hasSameConfigInfo(previousConfig)).findFirst().orElseThrow(
() -> new NoSuchPropertyException("Missing previously selected config"));
return previousUpdated;
}
private ICarOccupantZoneCallback getOccupantZoneCallback() {
ArgumentCaptor<ICarOccupantZoneCallback> captor =
ArgumentCaptor.forClass(ICarOccupantZoneCallback.class);
verify(mMockOccupantZoneService).registerCallback(captor.capture());
return captor.getValue();
}
private AudioServerStateCallback getAudioServerStateCallback() {
ArgumentCaptor<AudioServerStateCallback> captor = ArgumentCaptor.forClass(
AudioServerStateCallback.class);
verify(mAudioManager).setAudioServerStateCallback(any(), captor.capture());
return captor.getValue();
}
private String removeUpToEquals(String command) {
return command.replaceAll("^[^=]*=", "");
}
private String captureAudioMirrorInfoCommand(int count) {
ArgumentCaptor<String> capture = ArgumentCaptor.forClass(String.class);
verify(mAudioManager, times(count)).setParameters(capture.capture());
return capture.getValue();
}
private TestAudioZonesMirrorStatusCallbackCallback getAudioZonesMirrorStatusCallback(
CarAudioService service) {
TestAudioZonesMirrorStatusCallbackCallback callback =
new TestAudioZonesMirrorStatusCallbackCallback(/* count= */ 1);
service.registerAudioZonesMirrorStatusCallback(callback);
return callback;
}
private void assignOccupantToAudioZones() throws RemoteException {
ICarOccupantZoneCallback occupantZoneCallback = getOccupantZoneCallback();
occupantZoneCallback.onOccupantZoneConfigChanged(
CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
}
private void simulateLogoutPassengers() throws Exception {
when(mMockOccupantZoneService.getUserForOccupant(TEST_REAR_LEFT_OCCUPANT_ZONE_ID))
.thenReturn(UserManagerHelper.USER_NULL);
when(mMockOccupantZoneService.getUserForOccupant(TEST_REAR_RIGHT_OCCUPANT_ZONE_ID))
.thenReturn(UserManagerHelper.USER_NULL);
assignOccupantToAudioZones();
}
private void simulateLogoutRightPassengers() throws Exception {
when(mMockOccupantZoneService.getUserForOccupant(TEST_REAR_RIGHT_OCCUPANT_ZONE_ID))
.thenReturn(UserManagerHelper.USER_NULL);
assignOccupantToAudioZones();
}
private void simulatePassengersSwitch() throws Exception {
when(mMockOccupantZoneService.getUserForOccupant(TEST_REAR_LEFT_OCCUPANT_ZONE_ID))
.thenReturn(TEST_REAR_RIGHT_USER_ID);
when(mMockOccupantZoneService.getUserForOccupant(TEST_REAR_RIGHT_OCCUPANT_ZONE_ID))
.thenReturn(TEST_REAR_LEFT_USER_ID);
assignOccupantToAudioZones();
}
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(usageToMetadata(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 setUpCarAudioServiceWithoutMirroring() throws Exception {
setUpTempFileForAudioConfiguration(R.raw.car_audio_configuration_without_mirroring);
AudioDeviceInfo[] outputDevices = generateOutputDeviceInfos();
when(mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS)).thenReturn(outputDevices);
CarAudioService service = new CarAudioService(mMockContext, mTempCarAudioConfigFile
.getFile().getAbsolutePath(), mCarVolumeCallbackHandler);
service.init();
return service;
}
private CarAudioService setUpCarAudioServiceWithVersionTwoVolumeList() throws Exception {
setUpTempFileForAudioConfiguration(R.raw.car_audio_configuration);
when(mMockResources.getInteger(audioVolumeAdjustmentContextsVersion))
.thenReturn(AUDIO_CONTEXT_PRIORITY_LIST_VERSION_TWO);
CarAudioService service = new CarAudioService(mMockContext,
mTempCarAudioConfigFile.getFile().getAbsolutePath(), mCarVolumeCallbackHandler);
service.init();
return service;
}
private void setUpTempFileForAudioConfiguration(int resource) throws Exception {
try (InputStream configurationStream = mContext.getResources().openRawResource(resource)) {
mTempCarAudioConfigFile = new TemporaryFile("xml");
mTempCarAudioConfigFile.write(new String(configurationStream.readAllBytes()));
}
}
private CarAudioService setUpCarAudioServiceUsingCoreAudioRoutingAndVolume() throws Exception {
when(mMockResources.getBoolean(audioUseCoreVolume))
.thenReturn(/* audioUseCoreVolume= */ true);
when(mMockResources.getBoolean(audioUseCoreRouting))
.thenReturn(/* audioUseCoreRouting= */ true);
setUpTempFileForAudioConfiguration(
R.raw.car_audio_configuration_using_core_audio_routing_and_volume);
CarAudioService useCoreAudioCarAudioService = new CarAudioService(mMockContext,
mTempCarAudioConfigFile.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();
mNotificationOutpuBus = new AudioDeviceInfoBuilder()
.setAudioGains(new AudioGain[] {new GainBuilder().build()})
.setAddressName(NOTIFICATION_TEST_DEVICE)
.build();
mNavOutputDevice = new AudioDeviceInfoBuilder()
.setAudioGains(new AudioGain[] {new GainBuilder().build()})
.setAddressName(NAVIGATION_TEST_DEVICE)
.build();
mVoiceOutpuBus = new AudioDeviceInfoBuilder()
.setAudioGains(new AudioGain[] {new GainBuilder().build()})
.setAddressName(VOICE_TEST_DEVICE)
.build();
mSecondaryConfig0Group0Device = new AudioDeviceInfoBuilder()
.setAudioGains(new AudioGain[] {new GainBuilder().build()})
.setAddressName(SECONDARY_TEST_DEVICE_CONFIG_0)
.build();
mSecondaryConfig1Group0Device = new AudioDeviceInfoBuilder()
.setAudioGains(new AudioGain[] {new GainBuilder().build()})
.setAddressName(SECONDARY_TEST_DEVICE_CONFIG_1_0)
.build();
mSecondaryConfig1Group1Device = new AudioDeviceInfoBuilder()
.setAudioGains(new AudioGain[] {new GainBuilder().build()})
.setAddressName(SECONDARY_TEST_DEVICE_CONFIG_1_1)
.build();
mBTAudioDeviceInfo = new AudioDeviceInfoBuilder()
.setAudioGains(new AudioGain[] {new GainBuilder().build()})
.setAddressName(SECONDARY_TEST_DEVICE_CONFIG_1_1)
.setType(TYPE_BLUETOOTH_A2DP)
.build();
return new AudioDeviceInfo[] {
mMediaOutputDevice,
mNavOutputDevice,
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(),
mNotificationOutpuBus,
mVoiceOutpuBus,
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_CONFIG_0)
.build(),
mSecondaryConfig1Group0Device,
mSecondaryConfig1Group1Device,
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(),
new AudioDeviceInfoBuilder()
.setAudioGains(new AudioGain[] {new GainBuilder().build()})
.setAddressName(TEST_REAR_ROW_3_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);
doReturn(CoreAudioRoutingUtils.MUSIC_GROUP_ID)
.when(() -> CoreAudioHelper.getVolumeGroupIdForAudioAttributes(
CoreAudioRoutingUtils.MUSIC_ATTRIBUTES));
doReturn(CoreAudioRoutingUtils.MUSIC_ATTRIBUTES)
.when(() -> CoreAudioHelper.selectAttributesForVolumeGroupName(
CoreAudioRoutingUtils.MUSIC_GROUP_NAME));
doReturn(CoreAudioRoutingUtils.NAV_GROUP_ID)
.when(() -> CoreAudioHelper.getVolumeGroupIdForAudioAttributes(
CoreAudioRoutingUtils.NAV_ATTRIBUTES));
doReturn(CoreAudioRoutingUtils.NAV_ATTRIBUTES)
.when(() -> CoreAudioHelper.selectAttributesForVolumeGroupName(
CoreAudioRoutingUtils.NAV_GROUP_NAME));
doReturn(CoreAudioRoutingUtils.OEM_GROUP_ID)
.when(() -> CoreAudioHelper.getVolumeGroupIdForAudioAttributes(
CoreAudioRoutingUtils.OEM_ATTRIBUTES));
doReturn(CoreAudioRoutingUtils.OEM_ATTRIBUTES)
.when(() -> CoreAudioHelper.selectAttributesForVolumeGroupName(
CoreAudioRoutingUtils.OEM_GROUP_NAME));
}
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(CarAudioService service, int zoneId) {
CarAudioZoneConfigInfo currentZoneConfigInfo =
service.getCurrentAudioZoneConfigInfo(zoneId);
List<CarAudioZoneConfigInfo> zoneConfigInfos = service.getAudioZoneConfigInfos(zoneId);
for (int index = 0; index < zoneConfigInfos.size(); index++) {
if (currentZoneConfigInfo.equals(zoneConfigInfos.get(index))) {
continue;
}
return zoneConfigInfos.get(index);
}
return null;
}
private static final class TestAudioZoneConfigurationsChangeCallback
extends IAudioZoneConfigurationsChangeCallback.Stub {
private List<CarAudioZoneConfigInfo> mInfos;
private int mStatus = INVALID_STATUS;
private CountDownLatch mStatusLatch = new CountDownLatch(1);
@Override
public void onAudioZoneConfigurationsChanged(List<CarAudioZoneConfigInfo> configs,
int status) {
mInfos = configs;
mStatus = status;
mStatusLatch.countDown();
}
private void waitForCallback() throws Exception {
mStatusLatch.await(TEST_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
}
public void reset() {
mInfos = null;
mStatus = INVALID_STATUS;
mStatusLatch = new CountDownLatch(1);
}
}
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;
private DeathRecipient mDeathRecipient;
@Override
public void linkToDeath(@NonNull DeathRecipient recipient, int flags) {
mDeathRecipient = recipient;
super.linkToDeath(recipient, flags);
}
@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 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 void reset() {
mInfo = null;
mRequestId = INVALID_REQUEST_ID;
mStatus = INVALID_STATUS;
mStatusLatch = new CountDownLatch(1);
}
}
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) {
mZoneConfig = zoneConfig;
mIsSuccessful = isSuccessful;
mStatusLatch.countDown();
}
private void waitForCallback() throws Exception {
mStatusLatch.await(TEST_ZONE_CONFIG_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
}
CarAudioZoneConfigInfo getZoneConfig() {
return mZoneConfig;
}
boolean getSwitchStatus() {
return mIsSuccessful;
}
}
private static final class CarVolumeEventCallbackImpl extends ICarVolumeEventCallback.Stub {
private CountDownLatch mStatusLatch = new CountDownLatch(1);
private List<CarVolumeGroupEvent> mVolumeGroupEvents;
@Override
public void onVolumeGroupEvent(List<CarVolumeGroupEvent> volumeGroupEvents) {
mVolumeGroupEvents = volumeGroupEvents;
mStatusLatch.countDown();
}
@Override
public void onMasterMuteChanged(int zoneId, int flags) {
mStatusLatch.countDown();
}
private boolean waitForCallback() throws Exception {
return mStatusLatch.await(TEST_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
}
List<CarVolumeGroupEvent> getVolumeGroupEvents() {
return mVolumeGroupEvents;
}
public void reset() {
mStatusLatch = new CountDownLatch(1);
}
}
}