• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Copyright (C) 2022 The Android Open Source Project
3   *
4   * Licensed under the Apache License, Version 2.0 (the "License");
5   * you may not use this file except in compliance with the License.
6   * You may obtain a copy of the License at
7   *
8   *      http://www.apache.org/licenses/LICENSE-2.0
9   *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.android.car.audio;
18  
19  import static android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS;
20  import static android.car.Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME;
21  import static android.car.PlatformVersion.VERSION_CODES.UPSIDE_DOWN_CAKE_0;
22  import static android.car.media.CarAudioManager.AUDIO_FEATURE_AUDIO_MIRRORING;
23  import static android.car.media.CarAudioManager.AUDIO_FEATURE_DYNAMIC_ROUTING;
24  import static android.car.media.CarAudioManager.AUDIO_FEATURE_MIN_MAX_ACTIVATION_VOLUME;
25  import static android.car.media.CarAudioManager.AUDIO_FEATURE_OEM_AUDIO_SERVICE;
26  import static android.car.media.CarAudioManager.AUDIO_FEATURE_VOLUME_GROUP_EVENTS;
27  import static android.car.media.CarAudioManager.AUDIO_FEATURE_VOLUME_GROUP_MUTING;
28  import static android.car.media.CarAudioManager.AUDIO_MIRROR_CAN_ENABLE;
29  import static android.car.media.CarAudioManager.AUDIO_MIRROR_OUT_OF_OUTPUT_DEVICES;
30  import static android.car.media.CarAudioManager.CONFIG_STATUS_AUTO_SWITCHED;
31  import static android.car.media.CarAudioManager.CONFIG_STATUS_CHANGED;
32  import static android.car.media.CarAudioManager.INVALID_AUDIO_ZONE;
33  import static android.car.media.CarAudioManager.INVALID_REQUEST_ID;
34  import static android.car.media.CarAudioManager.INVALID_VOLUME_GROUP_ID;
35  import static android.car.media.CarAudioManager.PRIMARY_AUDIO_ZONE;
36  import static android.car.test.mocks.AndroidMockitoHelper.mockCarGetPlatformVersion;
37  import static android.car.test.mocks.AndroidMockitoHelper.mockContextCheckCallingOrSelfPermission;
38  import static android.content.pm.PackageManager.PERMISSION_DENIED;
39  import static android.content.pm.PackageManager.PERMISSION_GRANTED;
40  import static android.media.AudioAttributes.USAGE_ALARM;
41  import static android.media.AudioAttributes.USAGE_ANNOUNCEMENT;
42  import static android.media.AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY;
43  import static android.media.AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
44  import static android.media.AudioAttributes.USAGE_ASSISTANCE_SONIFICATION;
45  import static android.media.AudioAttributes.USAGE_ASSISTANT;
46  import static android.media.AudioAttributes.USAGE_CALL_ASSISTANT;
47  import static android.media.AudioAttributes.USAGE_EMERGENCY;
48  import static android.media.AudioAttributes.USAGE_GAME;
49  import static android.media.AudioAttributes.USAGE_MEDIA;
50  import static android.media.AudioAttributes.USAGE_NOTIFICATION;
51  import static android.media.AudioAttributes.USAGE_NOTIFICATION_EVENT;
52  import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
53  import static android.media.AudioAttributes.USAGE_SAFETY;
54  import static android.media.AudioAttributes.USAGE_UNKNOWN;
55  import static android.media.AudioAttributes.USAGE_VEHICLE_STATUS;
56  import static android.media.AudioAttributes.USAGE_VOICE_COMMUNICATION;
57  import static android.media.AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING;
58  import static android.media.AudioDeviceInfo.TYPE_BLUETOOTH_A2DP;
59  import static android.media.AudioDeviceInfo.TYPE_BUILTIN_MIC;
60  import static android.media.AudioDeviceInfo.TYPE_FM_TUNER;
61  import static android.media.AudioManager.AUDIOFOCUS_GAIN;
62  import static android.media.AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
63  import static android.media.AudioManager.AUDIOFOCUS_LOSS;
64  import static android.media.AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
65  import static android.media.AudioManager.AUDIOFOCUS_NONE;
66  import static android.media.AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
67  import static android.media.AudioManager.ERROR;
68  import static android.media.AudioManager.EXTRA_VOLUME_STREAM_TYPE;
69  import static android.media.AudioManager.FLAG_FROM_KEY;
70  import static android.media.AudioManager.FLAG_PLAY_SOUND;
71  import static android.media.AudioManager.FLAG_SHOW_UI;
72  import static android.media.AudioManager.MASTER_MUTE_CHANGED_ACTION;
73  import static android.media.AudioManager.STREAM_MUSIC;
74  import static android.media.AudioManager.SUCCESS;
75  import static android.media.AudioManager.VOLUME_CHANGED_ACTION;
76  import static android.media.audio.common.AudioDeviceDescription.CONNECTION_BUS;
77  import static android.media.audio.common.AudioDeviceType.OUT_DEVICE;
78  import static android.media.audio.common.AudioGainMode.JOINT;
79  import static android.media.audiopolicy.Flags.FLAG_ENABLE_FADE_MANAGER_CONFIGURATION;
80  import static android.os.Build.VERSION.SDK_INT;
81  import static android.view.KeyEvent.ACTION_DOWN;
82  import static android.view.KeyEvent.ACTION_UP;
83  import static android.view.KeyEvent.KEYCODE_UNKNOWN;
84  import static android.view.KeyEvent.KEYCODE_VOLUME_DOWN;
85  import static android.view.KeyEvent.KEYCODE_VOLUME_MUTE;
86  import static android.view.KeyEvent.KEYCODE_VOLUME_UP;
87  
88  import static com.android.car.R.bool.audioEnableVolumeKeyEventsToDynamicDevices;
89  import static com.android.car.R.bool.audioPersistMasterMuteState;
90  import static com.android.car.R.bool.audioUseCarVolumeGroupEvent;
91  import static com.android.car.R.bool.audioUseCarVolumeGroupMuting;
92  import static com.android.car.R.bool.audioUseCoreRouting;
93  import static com.android.car.R.bool.audioUseCoreVolume;
94  import static com.android.car.R.bool.audioUseDynamicRouting;
95  import static com.android.car.R.bool.audioUseFadeManagerConfiguration;
96  import static com.android.car.R.bool.audioUseHalDuckingSignals;
97  import static com.android.car.R.bool.audioUseMinMaxActivationVolume;
98  import static com.android.car.R.integer.audioVolumeAdjustmentContextsVersion;
99  import static com.android.car.R.integer.audioVolumeKeyEventTimeoutMs;
100  import static com.android.car.audio.CarAudioService.CAR_DEFAULT_AUDIO_ATTRIBUTE;
101  import static com.android.car.audio.CarHalAudioUtils.usageToMetadata;
102  import static com.android.car.audio.GainBuilder.DEFAULT_GAIN;
103  import static com.android.car.audio.GainBuilder.MAX_GAIN;
104  import static com.android.car.audio.GainBuilder.MIN_GAIN;
105  import static com.android.car.audio.GainBuilder.STEP_SIZE;
106  import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
107  import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
108  
109  import static org.junit.Assert.assertThrows;
110  import static org.mockito.ArgumentMatchers.any;
111  import static org.mockito.ArgumentMatchers.anyBoolean;
112  import static org.mockito.ArgumentMatchers.anyInt;
113  import static org.mockito.ArgumentMatchers.anyString;
114  import static org.mockito.ArgumentMatchers.eq;
115  import static org.mockito.Mockito.atLeastOnce;
116  import static org.mockito.Mockito.mock;
117  import static org.mockito.Mockito.never;
118  import static org.mockito.Mockito.reset;
119  import static org.mockito.Mockito.times;
120  import static org.mockito.Mockito.when;
121  
122  import android.annotation.NonNull;
123  import android.car.Car;
124  import android.car.CarOccupantZoneManager;
125  import android.car.ICarOccupantZoneCallback;
126  import android.car.VehicleAreaSeat;
127  import android.car.builtin.media.AudioManagerHelper;
128  import android.car.builtin.media.AudioManagerHelper.AudioPatchInfo;
129  import android.car.builtin.os.UserManagerHelper;
130  import android.car.feature.Flags;
131  import android.car.media.CarAudioManager;
132  import android.car.media.CarAudioPatchHandle;
133  import android.car.media.CarAudioZoneConfigInfo;
134  import android.car.media.CarVolumeGroupEvent;
135  import android.car.media.CarVolumeGroupInfo;
136  import android.car.media.IAudioZoneConfigurationsChangeCallback;
137  import android.car.media.IAudioZonesMirrorStatusCallback;
138  import android.car.media.IMediaAudioRequestStatusCallback;
139  import android.car.media.IPrimaryZoneMediaAudioRequestCallback;
140  import android.car.media.ISwitchAudioZoneConfigCallback;
141  import android.car.settings.CarSettings;
142  import android.car.test.mocks.AbstractExtendedMockitoTestCase;
143  import android.car.test.mocks.MockSettings;
144  import android.car.test.util.TemporaryFile;
145  import android.content.AttributionSource;
146  import android.content.BroadcastReceiver;
147  import android.content.ContentResolver;
148  import android.content.Context;
149  import android.content.Intent;
150  import android.content.pm.PackageManager;
151  import android.content.res.Resources;
152  import android.hardware.automotive.audiocontrol.AudioGainConfigInfo;
153  import android.hardware.automotive.audiocontrol.IAudioControl;
154  import android.hardware.automotive.audiocontrol.Reasons;
155  import android.media.AudioAttributes;
156  import android.media.AudioDeviceAttributes;
157  import android.media.AudioDeviceCallback;
158  import android.media.AudioDeviceInfo;
159  import android.media.AudioFocusInfo;
160  import android.media.AudioGain;
161  import android.media.AudioManager;
162  import android.media.AudioManager.AudioPlaybackCallback;
163  import android.media.AudioManager.AudioServerStateCallback;
164  import android.media.AudioPlaybackConfiguration;
165  import android.media.IAudioService;
166  import android.media.audio.common.AudioDevice;
167  import android.media.audio.common.AudioDeviceAddress;
168  import android.media.audio.common.AudioDeviceDescription;
169  import android.media.audio.common.AudioPort;
170  import android.media.audio.common.AudioPortDeviceExt;
171  import android.media.audio.common.AudioPortExt;
172  import android.media.audiopolicy.AudioPolicy;
173  import android.net.Uri;
174  import android.os.Binder;
175  import android.os.Build;
176  import android.os.Handler;
177  import android.os.HandlerThread;
178  import android.os.IBinder;
179  import android.os.RemoteException;
180  import android.os.ServiceManager;
181  import android.os.SystemProperties;
182  import android.os.UserHandle;
183  import android.platform.test.flag.junit.SetFlagsRule;
184  import android.provider.Settings;
185  import android.telephony.SubscriptionManager;
186  import android.telephony.TelephonyCallback;
187  import android.telephony.TelephonyManager;
188  import android.util.Log;
189  import android.util.NoSuchPropertyException;
190  import android.view.KeyEvent;
191  
192  import androidx.test.core.app.ApplicationProvider;
193  
194  import com.android.car.CarInputService;
195  import com.android.car.CarInputService.KeyEventListener;
196  import com.android.car.CarLocalServices;
197  import com.android.car.CarOccupantZoneService;
198  import com.android.car.CarServiceUtils;
199  import com.android.car.R;
200  import com.android.car.audio.hal.AudioControlFactory;
201  import com.android.car.audio.hal.AudioControlWrapper;
202  import com.android.car.audio.hal.AudioControlWrapper.AudioControlDeathRecipient;
203  import com.android.car.audio.hal.AudioControlWrapperAidl;
204  import com.android.car.audio.hal.HalAudioDeviceInfo;
205  import com.android.car.audio.hal.HalAudioGainCallback;
206  import com.android.car.audio.hal.HalAudioModuleChangeCallback;
207  import com.android.car.audio.hal.HalFocusListener;
208  import com.android.car.oem.CarOemAudioDuckingProxyService;
209  import com.android.car.oem.CarOemAudioFocusProxyService;
210  import com.android.car.oem.CarOemAudioVolumeProxyService;
211  import com.android.car.oem.CarOemProxyService;
212  import com.android.car.power.CarPowerManagementService;
213  
214  import org.junit.After;
215  import org.junit.Before;
216  import org.junit.Rule;
217  import org.junit.Test;
218  import org.mockito.ArgumentCaptor;
219  import org.mockito.Captor;
220  import org.mockito.Mock;
221  
222  import java.io.InputStream;
223  import java.util.ArrayList;
224  import java.util.Arrays;
225  import java.util.Collections;
226  import java.util.List;
227  import java.util.concurrent.CountDownLatch;
228  import java.util.concurrent.TimeUnit;
229  
230  public final class CarAudioServiceUnitTest extends AbstractExtendedMockitoTestCase {
231      private static final String TAG = CarAudioServiceUnitTest.class.getSimpleName();
232      private static final long TEST_CALLBACK_TIMEOUT_MS = 100;
233      private static final long TEST_ZONE_CONFIG_CALLBACK_TIMEOUT_MS = 500;
234      private static final int VOLUME_KEY_EVENT_TIMEOUT_MS = 3000;
235      private static final int AUDIO_CONTEXT_PRIORITY_LIST_VERSION_ONE = 1;
236      private static final int AUDIO_CONTEXT_PRIORITY_LIST_VERSION_TWO = 2;
237      private static final String MEDIA_TEST_DEVICE = "media_bus_device";
238      private static final String OEM_TEST_DEVICE = "oem_bus_device";
239      private static final String MIRROR_TEST_DEVICE = "mirror_bus_device";
240      private static final String NAVIGATION_TEST_DEVICE = "navigation_bus_device";
241      private static final String CALL_TEST_DEVICE = "call_bus_device";
242      private static final String NOTIFICATION_TEST_DEVICE = "notification_bus_device";
243      private static final String VOICE_TEST_DEVICE = "voice_bus_device";
244      private static final String RING_TEST_DEVICE = "ring_bus_device";
245      private static final String ALARM_TEST_DEVICE = "alarm_bus_device";
246      private static final String SYSTEM_BUS_DEVICE = "system_bus_device";
247      private static final String SECONDARY_TEST_DEVICE_CONFIG_0 = "secondary_zone_bus_100";
248      private static final String SECONDARY_TEST_DEVICE_CONFIG_1_0 = "secondary_zone_bus_200";
249      private static final String SECONDARY_TEST_DEVICE_CONFIG_1_1 = "secondary_zone_bus_201";
250      private static final String TEST_BT_DEVICE = "08:67:53:09";
251      private static final String TERTIARY_TEST_DEVICE_1 = "tertiary_zone_bus_100";
252      private static final String TERTIARY_TEST_DEVICE_2 = "tertiary_zone_bus_200";
253      private static final String QUATERNARY_TEST_DEVICE_1 = "quaternary_zone_bus_1";
254      private static final String TEST_REAR_ROW_3_DEVICE = "rear_row_three_zone_bus_1";
255      private static final String PRIMARY_ZONE_MICROPHONE_ADDRESS = "Built-In Mic";
256      private static final String PRIMARY_ZONE_FM_TUNER_ADDRESS = "FM Tuner";
257      private static final String SECONDARY_ZONE_CONFIG_NAME_1 = "secondary zone config 1";
258      private static final String SECONDARY_ZONE_CONFIG_NAME_2 = "secondary zone config 2";
259      public static final String SECONDARY_ZONE_BT_CONFIG_NAME = "secondary BT zone config 0";
260      private static final String DEFAULT_CONFIG_NAME_DYNAMIC_DEVICES = "primary zone config 0";
261      private static final String PRIMARY_CONFIG_NAME_DYNAMIC_DEVICES = "primary zone BT media";
262      private static final String TERTIARY_CONFIG_NAME_DYNAMIC_DEVICES =
263              "primary zone headphones media";
264      private static final String MIRROR_OFF_SIGNAL = "mirroring=off";
265      // From the car audio configuration file in /res/raw/car_audio_configuration.xml
266      private static final int TEST_REAR_LEFT_ZONE_ID = 1;
267      private static final int TEST_REAR_RIGHT_ZONE_ID = 2;
268      private static final int TEST_FRONT_ZONE_ID = 3;
269      private static final int TEST_REAR_ROW_3_ZONE_ID = 4;
270      public static final int[] TEST_MIRROR_AUDIO_ZONES = new int[]{TEST_REAR_LEFT_ZONE_ID,
271              TEST_REAR_RIGHT_ZONE_ID};
272      private static final int OUT_OF_RANGE_ZONE = TEST_REAR_ROW_3_ZONE_ID + 1;
273      private static final int PRIMARY_ZONE_VOLUME_GROUP_COUNT = 4;
274      private static final int SECONDARY_ZONE_VOLUME_GROUP_COUNT = 1;
275      private static final int SECONDARY_ZONE_VOLUME_GROUP_ID = SECONDARY_ZONE_VOLUME_GROUP_COUNT - 1;
276      private static final int TEST_PRIMARY_ZONE_GROUP_0 = 0;
277      private static final int TEST_PRIMARY_ZONE_GROUP_1 = 1;
278      private static final int TEST_PRIMARY_ZONE_GROUP_2 = 2;
279      private static final int TEST_SECONDARY_ZONE_GROUP_0 = 0;
280      private static final int TEST_SECONDARY_ZONE_GROUP_1 = 1;
281      private static final int TEST_FLAGS = 0;
282      private static final float TEST_VALUE = -.75f;
283      private static final float INVALID_TEST_VALUE = -1.5f;
284      private static final int TEST_DISPLAY_TYPE = 2;
285      private static final int TEST_SEAT = 2;
286      private static final int PRIMARY_OCCUPANT_ZONE = 0;
287      private static final int INVALID_STATUS = 0;
288  
289      private static final int TEST_DRIVER_OCCUPANT_ZONE_ID = 1;
290      private static final int TEST_REAR_LEFT_OCCUPANT_ZONE_ID = 2;
291      private static final int TEST_REAR_RIGHT_OCCUPANT_ZONE_ID = 3;
292      private static final int TEST_FRONT_OCCUPANT_ZONE_ID = 4;
293      private static final int TEST_REAR_ROW_3_OCCUPANT_ZONE_ID = 5;
294      private static final int TEST_UNASSIGNED_OCCUPANT_ZONE_ID = 6;
295  
296      private static final int TEST_MEDIA_PORT_ID = 0;
297      private static final int TEST_NAV_PORT_ID = 1;
298      private static final String TEST_MEDIA_PORT_NAME = "Media bus";
299      private static final String TEST_NAV_PORT_NAME = "Nav bus";
300      private static final int TEST_GAIN_MIN_VALUE = -3000;
301      private static final int TEST_GAIN_MAX_VALUE = -1000;
302      private static final int TEST_GAIN_DEFAULT_VALUE = -2000;
303      private static final int TEST_GAIN_STEP_VALUE = 2;
304  
305      private static final int TEST_PLAYBACK_UID = 10101;
306  
307      private static final CarOccupantZoneManager.OccupantZoneInfo TEST_DRIVER_OCCUPANT =
308              getOccupantInfo(TEST_DRIVER_OCCUPANT_ZONE_ID,
309                      CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER,
310                      VehicleAreaSeat.SEAT_ROW_1_LEFT);
311      private static final CarOccupantZoneManager.OccupantZoneInfo
312              TEST_REAR_RIGHT_PASSENGER_OCCUPANT =
313              getOccupantInfo(TEST_REAR_RIGHT_OCCUPANT_ZONE_ID,
314                      CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER,
315                      VehicleAreaSeat.SEAT_ROW_2_RIGHT);
316      private static final CarOccupantZoneManager.OccupantZoneInfo
317              TEST_FRONT_PASSENGER_OCCUPANT =
318              getOccupantInfo(TEST_FRONT_OCCUPANT_ZONE_ID,
319                      CarOccupantZoneManager.OCCUPANT_TYPE_FRONT_PASSENGER,
320                      VehicleAreaSeat.SEAT_ROW_1_RIGHT);
321      private static final CarOccupantZoneManager.OccupantZoneInfo
322              TEST_REAR_LEFT_PASSENGER_OCCUPANT =
323              getOccupantInfo(TEST_REAR_LEFT_OCCUPANT_ZONE_ID,
324                      CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER,
325                      VehicleAreaSeat.SEAT_ROW_2_LEFT);
326  
327      private static final CarOccupantZoneManager.OccupantZoneInfo
328              TEST_REAR_ROW_3_PASSENGER_OCCUPANT =
329              getOccupantInfo(TEST_REAR_ROW_3_OCCUPANT_ZONE_ID,
330                      CarOccupantZoneManager.OCCUPANT_TYPE_REAR_PASSENGER,
331                      VehicleAreaSeat.SEAT_ROW_3_LEFT);
332  
333      private static final String PROPERTY_RO_ENABLE_AUDIO_PATCH =
334              "ro.android.car.audio.enableaudiopatch";
335  
336      private static final int MEDIA_APP_UID = 1086753;
337      private static final int TEST_REAR_RIGHT_UID = 1286753;
338      private static final String MEDIA_CLIENT_ID = "media-client-id";
339      private static final String MEDIA_PACKAGE_NAME = "com.android.car.audio";
340      private static final int MEDIA_EMPTY_FLAG = 0;
341      private static final String REGISTRATION_ID = "meh";
342      private static final int MEDIA_VOLUME_GROUP_ID = 0;
343      private static final int NAVIGATION_VOLUME_GROUP_ID = 1;
344      private static final int INVALID_USAGE = -1;
345      private static final int INVALID_AUDIO_FEATURE = -1;
346      private static final int TEST_DRIVER_USER_ID = 10;
347      private static final int TEST_REAR_LEFT_USER_ID = 11;
348      private static final int TEST_REAR_RIGHT_USER_ID = 12;
349      private static final int TEST_FRONT_PASSENGER_USER_ID = 13;
350      private static final int TEST_REAR_ROW_3_PASSENGER_USER_ID = 14;
351      private static final int TEST_GAIN_INDEX = 4;
352  
353      // TODO(b/273800524): create a utility test class for audio attributes.
354      private static final AudioAttributes ATTRIBUTES_UNKNOWN =
355              CarAudioContext.getAudioAttributeFromUsage(USAGE_UNKNOWN);
356      private static final AudioAttributes ATTRIBUTES_GAME =
357              CarAudioContext.getAudioAttributeFromUsage(USAGE_GAME);
358      private static final AudioAttributes ATTRIBUTES_MEDIA =
359              CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA);
360      private static final AudioAttributes ATTRIBUTES_NOTIFICATION =
361              CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION);
362      private static final AudioAttributes ATTRIBUTES_NOTIFICATION_EVENT =
363              CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION_EVENT);
364      private static final AudioAttributes ATTRIBUTES_ANNOUNCEMENT =
365              CarAudioContext.getAudioAttributeFromUsage(USAGE_ANNOUNCEMENT);
366      private static final AudioAttributes ATTRIBUTES_ASSISTANCE_NAVIGATION_GUIDANCE =
367              CarAudioContext.getAudioAttributeFromUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE);
368      private static final AudioAttributes ATTRIBUTES_ASSISTANCE_ACCESSIBILITY =
369              CarAudioContext.getAudioAttributeFromUsage(USAGE_ASSISTANCE_ACCESSIBILITY);
370      private static final AudioAttributes ATTRIBUTES_ASSISTANT =
371              CarAudioContext.getAudioAttributeFromUsage(USAGE_ASSISTANT);
372      private static final AudioAttributes ATTRIBUTES_NOTIFICATION_RINGTONE =
373              CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION_RINGTONE);
374      private static final AudioAttributes ATTRIBUTES_VOICE_COMMUNICATION =
375              CarAudioContext.getAudioAttributeFromUsage(USAGE_VOICE_COMMUNICATION);
376      private static final AudioAttributes ATTRIBUTES_CALL_ASSISTANT =
377              CarAudioContext.getAudioAttributeFromUsage(USAGE_CALL_ASSISTANT);
378      private static final AudioAttributes ATTRIBUTES_VOICE_COMMUNICATION_SIGNALLING =
379              CarAudioContext.getAudioAttributeFromUsage(USAGE_VOICE_COMMUNICATION_SIGNALLING);
380      private static final AudioAttributes ATTRIBUTES_ALARM =
381              CarAudioContext.getAudioAttributeFromUsage(USAGE_ALARM);
382      private static final AudioAttributes ATTRIBUTES_ASSISTANCE_SONIFICATION =
383              CarAudioContext.getAudioAttributeFromUsage(USAGE_ASSISTANCE_SONIFICATION);
384      private static final AudioAttributes ATTRIBUTES_EMERGENCY =
385              CarAudioContext.getAudioAttributeFromUsage(USAGE_EMERGENCY);
386      private static final AudioAttributes ATTRIBUTES_SAFETY =
387              CarAudioContext.getAudioAttributeFromUsage(USAGE_SAFETY);
388      private static final AudioAttributes ATTRIBUTES_VEHICLE_STATUS =
389              CarAudioContext.getAudioAttributeFromUsage(USAGE_VEHICLE_STATUS);
390  
391      private static final List<AudioAttributes> TEST_PRIMARY_ZONE_AUDIO_ATTRIBUTES_0 = List.of(
392              ATTRIBUTES_UNKNOWN, ATTRIBUTES_GAME, ATTRIBUTES_MEDIA, ATTRIBUTES_NOTIFICATION,
393              ATTRIBUTES_NOTIFICATION_EVENT, ATTRIBUTES_ANNOUNCEMENT);
394  
395      private static final List<AudioAttributes> TEST_PRIMARY_ZONE_AUDIO_ATTRIBUTES_1 = List.of(
396              ATTRIBUTES_ASSISTANCE_NAVIGATION_GUIDANCE, ATTRIBUTES_ASSISTANCE_ACCESSIBILITY,
397              ATTRIBUTES_ASSISTANT);
398  
399      private static final List<AudioAttributes> TEST_SECONDARY_ZONE_AUDIO_ATTRIBUTES_DEFAULT =
400              List.of(ATTRIBUTES_UNKNOWN, ATTRIBUTES_GAME, ATTRIBUTES_MEDIA,
401                      ATTRIBUTES_ASSISTANCE_NAVIGATION_GUIDANCE, ATTRIBUTES_ASSISTANCE_ACCESSIBILITY,
402                      ATTRIBUTES_ASSISTANT, ATTRIBUTES_NOTIFICATION_RINGTONE,
403                      ATTRIBUTES_VOICE_COMMUNICATION, ATTRIBUTES_CALL_ASSISTANT,
404                      ATTRIBUTES_VOICE_COMMUNICATION_SIGNALLING, ATTRIBUTES_ALARM,
405                      ATTRIBUTES_NOTIFICATION, ATTRIBUTES_NOTIFICATION_EVENT,
406                      ATTRIBUTES_ASSISTANCE_SONIFICATION, ATTRIBUTES_EMERGENCY, ATTRIBUTES_SAFETY,
407                      ATTRIBUTES_VEHICLE_STATUS, ATTRIBUTES_ANNOUNCEMENT);
408  
409      private static final List<AudioAttributes> TEST_SECONDARY_ZONE_AUDIO_ATTRIBUTES_0 = List.of(
410              ATTRIBUTES_UNKNOWN, ATTRIBUTES_GAME, ATTRIBUTES_MEDIA,
411              ATTRIBUTES_ASSISTANCE_NAVIGATION_GUIDANCE, ATTRIBUTES_ASSISTANCE_ACCESSIBILITY,
412              ATTRIBUTES_ASSISTANT, ATTRIBUTES_NOTIFICATION, ATTRIBUTES_NOTIFICATION_EVENT,
413              ATTRIBUTES_ANNOUNCEMENT);
414  
415      private static final List<AudioAttributes> TEST_SECONDARY_ZONE_AUDIO_ATTRIBUTES_1 = List.of(
416              ATTRIBUTES_NOTIFICATION_RINGTONE, ATTRIBUTES_VOICE_COMMUNICATION,
417              ATTRIBUTES_CALL_ASSISTANT, ATTRIBUTES_VOICE_COMMUNICATION_SIGNALLING, ATTRIBUTES_ALARM,
418              ATTRIBUTES_ASSISTANCE_SONIFICATION, ATTRIBUTES_EMERGENCY, ATTRIBUTES_SAFETY,
419              ATTRIBUTES_VEHICLE_STATUS);
420  
421      private static final AudioFocusInfo TEST_AUDIO_FOCUS_INFO =
422              new AudioFocusInfo(CarAudioContext
423                      .getAudioAttributeFromUsage(USAGE_VOICE_COMMUNICATION), MEDIA_APP_UID,
424              MEDIA_CLIENT_ID, "com.android.car.audio",
425              AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, AUDIOFOCUS_NONE, /* flags= */ 0,
426              Build.VERSION.SDK_INT);
427  
428      private static final AudioFocusInfo TEST_REAR_RIGHT_AUDIO_FOCUS_INFO =
429              new AudioFocusInfo(CarAudioContext
430              .getAudioAttributeFromUsage(USAGE_MEDIA), TEST_REAR_RIGHT_UID,
431              MEDIA_CLIENT_ID, "com.android.car.audio",
432              AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, AUDIOFOCUS_NONE, /* flags= */ 0,
433              Build.VERSION.SDK_INT);
434  
435      private static final int AUDIO_SERVICE_POLICY_REGISTRATIONS = 3;
436      private static final int AUDIO_SERVICE_POLICY_REGISTRATIONS_WITH_FADE_MANAGER = 4;
437      private static final int AUDIO_SERVICE_CALLBACKS_REGISTRATION = 1;
438  
439      private HandlerThread mHandlerThread;
440      private Handler mHandler;
441  
442      @Mock
443      private Context mMockContext;
444      @Mock
445      private TelephonyManager mMockTelephonyManagerWithoutSubscriptionId;
446      @Mock
447      private TelephonyManager mMockTelephonyManager;
448      @Mock
449      private AudioManagerWrapper mAudioManager;
450      @Mock
451      private Resources mMockResources;
452      @Mock
453      private ContentResolver mMockContentResolver;
454      @Mock
455      private AttributionSource mMockAttributionSource;
456      @Mock
457      IBinder mBinder;
458      @Mock
459      IBinder mVolumeCallbackBinder;
460      @Mock
461      IAudioControl mAudioControl;
462      @Mock
463      private PackageManager mMockPackageManager;
464      @Mock
465      private CarOccupantZoneService mMockOccupantZoneService;
466      @Mock
467      private CarOemProxyService mMockCarOemProxyService;
468      @Mock
469      private IAudioService mMockAudioService;
470      @Mock
471      private Uri mNavSettingUri;
472      @Mock
473      private AudioControlWrapperAidl mAudioControlWrapperAidl;
474      @Mock
475      private CarVolumeCallbackHandler mCarVolumeCallbackHandler;
476      @Mock
477      private CarInputService mMockCarInputService;
478      @Mock
479      private CarPowerManagementService mMockPowerService;
480  
481      // Not used directly, but sets proper mockStatic() expectations on Settings
482      @SuppressWarnings("UnusedVariable")
483      private MockSettings mMockSettings;
484  
485      private boolean mPersistMasterMute = true;
486      private boolean mUseDynamicRouting = true;
487      private boolean mUseHalAudioDucking = true;
488      private boolean mUseCarVolumeGroupMuting = true;
489      private boolean mUseCarVolumeGroupEvents = true;
490      private boolean mUseMinMaxActivationVolume = true;
491      private boolean mEnableVolumeKeyEventsToDynamicDevices = false;
492  
493  
494      private TemporaryFile mTempCarAudioConfigFile;
495      private TemporaryFile mTempCarAudioFadeConfigFile;
496  
497      private Context mContext;
498      private AudioDeviceInfo mMicrophoneInputDevice;
499      private AudioDeviceInfo mFmTunerInputDevice;
500      private AudioDeviceInfo mMediaOutputDevice;
501      private AudioDeviceInfo mNotificationOutpuBus;
502      private AudioDeviceInfo mNavOutputDevice;
503      private AudioDeviceInfo mVoiceOutpuBus;
504      private AudioDeviceInfo mSecondaryConfig0Group0Device;
505      private AudioDeviceInfo mSecondaryConfig1Group0Device;
506      private AudioDeviceInfo mSecondaryConfig1Group1Device;
507  
508      private AudioDeviceInfo mBTAudioDeviceInfo;
509  
510      private CarVolumeGroupInfo mTestPrimaryZoneVolumeInfo0;
511      private CarVolumeGroupInfo mTestPrimaryZoneUmMutedVolueInfo0;
512      private CarVolumeGroupInfo mTestPrimaryZoneVolumeInfo1;
513      private CarVolumeGroupInfo mTestSecondaryConfig0VolumeGroup0Info;
514      private CarVolumeGroupInfo mTestSecondaryZoneConfig1VolumeInfo0;
515      private CarVolumeGroupInfo mTestSecondaryZoneConfig1VolumeInfo1;
516  
517      private CarVolumeGroupEvent mTestCarVolumeGroupEvent;
518      private CarVolumeGroupEvent mTestCarMuteGroupEvent;
519      private CarVolumeGroupEvent mTestCarZoneReconfigurationEvent;
520  
521      @Captor
522      private ArgumentCaptor<BroadcastReceiver> mVolumeReceiverCaptor;
523  
524      private int mRegistrationCount = 0;
525      private List<Integer> mAudioPolicyRegistrationStatus = new ArrayList<>();
526  
527      @Rule
528      public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
529  
CarAudioServiceUnitTest()530      public CarAudioServiceUnitTest() {
531          super(CarAudioService.TAG);
532      }
533  
534      @Override
onSessionBuilder(CustomMockitoSessionBuilder session)535      protected void onSessionBuilder(CustomMockitoSessionBuilder session) {
536          mMockSettings = new MockSettings(session);
537          session
538                  .spyStatic(SubscriptionManager.class)
539                  .spyStatic(AudioManagerWrapper.class)
540                  .spyStatic(AudioManagerHelper.class)
541                  .spyStatic(AudioControlWrapperAidl.class)
542                  .spyStatic(CoreAudioHelper.class)
543                  .spyStatic(AudioControlFactory.class)
544                  .spyStatic(SystemProperties.class)
545                  .spyStatic(ServiceManager.class)
546                  .spyStatic(Car.class);
547      }
548  
549      @Before
setUp()550      public void setUp() throws Exception {
551          mHandlerThread = CarServiceUtils.getHandlerThread(CarAudioService.class.getSimpleName());
552          mHandler = new Handler(mHandlerThread.getLooper());
553          mContext = ApplicationProvider.getApplicationContext();
554  
555          mockCarGetPlatformVersion(UPSIDE_DOWN_CAKE_0);
556  
557          mockCoreAudioRoutingAndVolume();
558          mockGrantCarControlAudioSettingsPermission();
559  
560          setUpAudioControlHAL();
561          setUpService();
562  
563          when(Settings.Secure.getUriFor(
564                  CarSettings.Secure.KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL))
565                  .thenReturn(mNavSettingUri);
566      }
567  
568      @After
tearDown()569      public void tearDown() throws Exception {
570          if (mTempCarAudioConfigFile != null) {
571              mTempCarAudioConfigFile.close();
572          }
573          if (mTempCarAudioFadeConfigFile != null) {
574              mTempCarAudioFadeConfigFile.close();
575          }
576          CarLocalServices.removeServiceForTest(CarOemProxyService.class);
577          CarLocalServices.removeServiceForTest(CarOccupantZoneService.class);
578          CarLocalServices.removeServiceForTest(CarPowerManagementService.class);
579      }
580  
setUpAudioControlHAL()581      private void setUpAudioControlHAL() {
582          when(mBinder.queryLocalInterface(anyString())).thenReturn(mAudioControl);
583          doReturn(mBinder).when(AudioControlWrapperAidl::getService);
584          when(mAudioControlWrapperAidl.supportsFeature(
585                  AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_DUCKING)).thenReturn(true);
586          when(mAudioControlWrapperAidl.supportsFeature(
587                  AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_FOCUS)).thenReturn(true);
588          when(mAudioControlWrapperAidl.supportsFeature(
589                  AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_GAIN_CALLBACK)).thenReturn(true);
590          when(mAudioControlWrapperAidl.supportsFeature(
591                  AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_GROUP_MUTING)).thenReturn(true);
592          when(mAudioControlWrapperAidl.supportsFeature(
593                  AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_MODULE_CALLBACK)).thenReturn(true);
594          doReturn(mAudioControlWrapperAidl)
595                  .when(AudioControlFactory::newAudioControl);
596      }
597  
setUpService()598      private void setUpService() throws Exception {
599          doReturn(0).when(() -> SubscriptionManager.getDefaultDataSubscriptionId());
600          when(mMockContext.getSystemService(TelephonyManager.class))
601                  .thenReturn(mMockTelephonyManagerWithoutSubscriptionId);
602          when(mMockTelephonyManagerWithoutSubscriptionId.createForSubscriptionId(anyInt()))
603                  .thenReturn(mMockTelephonyManager);
604  
605          when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
606          when(mMockContext.getAttributionSource()).thenReturn(mMockAttributionSource);
607          doReturn(true)
608                  .when(() -> AudioManagerHelper
609                          .setAudioDeviceGain(any(), any(), anyInt(), anyBoolean()));
610          doReturn(true)
611                  .when(() -> SystemProperties.getBoolean(PROPERTY_RO_ENABLE_AUDIO_PATCH, false));
612  
613          when(mMockOccupantZoneService.getUserForOccupant(TEST_DRIVER_OCCUPANT_ZONE_ID))
614                  .thenReturn(TEST_DRIVER_USER_ID);
615          when(mMockOccupantZoneService.getAudioZoneIdForOccupant(TEST_DRIVER_OCCUPANT_ZONE_ID))
616                  .thenReturn(PRIMARY_AUDIO_ZONE);
617          when(mMockOccupantZoneService.getOccupantZoneForUser(UserHandle.of(TEST_DRIVER_USER_ID)))
618                  .thenReturn(TEST_DRIVER_OCCUPANT);
619  
620          when(mMockOccupantZoneService.getUserForOccupant(TEST_REAR_LEFT_OCCUPANT_ZONE_ID))
621                  .thenReturn(TEST_REAR_LEFT_USER_ID);
622          when(mMockOccupantZoneService.getUserForOccupant(TEST_REAR_RIGHT_OCCUPANT_ZONE_ID))
623                  .thenReturn(TEST_REAR_RIGHT_USER_ID);
624          when(mMockOccupantZoneService.getUserForOccupant(TEST_FRONT_OCCUPANT_ZONE_ID))
625                  .thenReturn(TEST_FRONT_PASSENGER_USER_ID);
626          when(mMockOccupantZoneService.getUserForOccupant(TEST_REAR_ROW_3_OCCUPANT_ZONE_ID))
627                  .thenReturn(TEST_REAR_ROW_3_PASSENGER_USER_ID);
628          when(mMockOccupantZoneService.getAudioZoneIdForOccupant(TEST_REAR_LEFT_OCCUPANT_ZONE_ID))
629                  .thenReturn(TEST_REAR_LEFT_ZONE_ID);
630          when(mMockOccupantZoneService.getAudioZoneIdForOccupant(TEST_REAR_RIGHT_OCCUPANT_ZONE_ID))
631                  .thenReturn(TEST_REAR_RIGHT_ZONE_ID);
632          when(mMockOccupantZoneService.getAudioZoneIdForOccupant(TEST_FRONT_OCCUPANT_ZONE_ID))
633                  .thenReturn(TEST_FRONT_PASSENGER_USER_ID);
634          when(mMockOccupantZoneService.getAudioZoneIdForOccupant(TEST_REAR_ROW_3_ZONE_ID))
635                  .thenReturn(TEST_REAR_ROW_3_PASSENGER_USER_ID);
636          when(mMockOccupantZoneService.getOccupantZoneForUser(
637                  UserHandle.of(TEST_REAR_RIGHT_USER_ID))).thenReturn(
638                  TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
639          when(mMockOccupantZoneService.getOccupantZoneForUser(
640                  UserHandle.of(TEST_FRONT_PASSENGER_USER_ID))).thenReturn(
641                  TEST_FRONT_PASSENGER_OCCUPANT);
642          when(mMockOccupantZoneService.getOccupantZoneForUser(
643                  UserHandle.of(TEST_REAR_LEFT_USER_ID))).thenReturn(
644                  TEST_REAR_LEFT_PASSENGER_OCCUPANT);
645          when(mMockOccupantZoneService.getOccupantForAudioZoneId(TEST_REAR_ROW_3_ZONE_ID))
646                  .thenReturn(TEST_REAR_ROW_3_PASSENGER_OCCUPANT);
647          when(mMockOccupantZoneService.getOccupantForAudioZoneId(TEST_REAR_RIGHT_ZONE_ID))
648                  .thenReturn(TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
649          when(mMockOccupantZoneService.getOccupantForAudioZoneId(TEST_FRONT_ZONE_ID))
650                  .thenReturn(TEST_FRONT_PASSENGER_OCCUPANT);
651          when(mMockOccupantZoneService.getOccupantForAudioZoneId(TEST_REAR_LEFT_ZONE_ID))
652                  .thenReturn(TEST_REAR_LEFT_PASSENGER_OCCUPANT);
653          when(mMockOccupantZoneService.getOccupantForAudioZoneId(TEST_REAR_ROW_3_ZONE_ID))
654                  .thenReturn(TEST_REAR_ROW_3_PASSENGER_OCCUPANT);
655  
656          // Initially set occupant zone service at uninitialized
657          when(mMockOccupantZoneService.getDriverUserId()).thenReturn(UserHandle.USER_SYSTEM);
658  
659          CarLocalServices.removeServiceForTest(CarOccupantZoneService.class);
660          CarLocalServices.addService(CarOccupantZoneService.class, mMockOccupantZoneService);
661          CarLocalServices.removeServiceForTest(CarInputService.class);
662          CarLocalServices.addService(CarInputService.class, mMockCarInputService);
663          CarLocalServices.removeServiceForTest(CarPowerManagementService.class);
664          CarLocalServices.addService(CarPowerManagementService.class, mMockPowerService);
665  
666          CarLocalServices.removeServiceForTest(CarOemProxyService.class);
667          CarLocalServices.addService(CarOemProxyService.class, mMockCarOemProxyService);
668  
669          setUpAudioManager();
670  
671          setUpResources();
672      }
673  
setUpAudioManager()674      private void setUpAudioManager() throws Exception {
675          AudioDeviceInfo[] outputDevices = generateOutputDeviceInfos();
676          AudioDeviceInfo[] inputDevices = generateInputDeviceInfos();
677          mTestPrimaryZoneVolumeInfo0 =
678                  new CarVolumeGroupInfo.Builder("config 0 group " + TEST_PRIMARY_ZONE_GROUP_0,
679                          PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0).setMuted(true)
680                          .setMinVolumeGainIndex(0).setMaxVolumeGainIndex(MAX_GAIN / STEP_SIZE)
681                          .setVolumeGainIndex(DEFAULT_GAIN / STEP_SIZE)
682                          .setAudioAttributes(TEST_PRIMARY_ZONE_AUDIO_ATTRIBUTES_0)
683                          .setAudioDeviceAttributes(List.of(
684                                  new AudioDeviceAttributes(mNotificationOutpuBus),
685                                  new AudioDeviceAttributes(mMediaOutputDevice)))
686                          .setMinActivationVolumeGainIndex(0)
687                          .setMaxActivationVolumeGainIndex(MAX_GAIN / STEP_SIZE).build();
688          mTestPrimaryZoneUmMutedVolueInfo0 =
689                  new CarVolumeGroupInfo.Builder("config 0 group " + TEST_PRIMARY_ZONE_GROUP_0,
690                          PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0).setMuted(false)
691                          .setMinVolumeGainIndex(0).setMaxVolumeGainIndex(MAX_GAIN / STEP_SIZE)
692                          .setVolumeGainIndex(DEFAULT_GAIN / STEP_SIZE)
693                          .setAudioAttributes(TEST_PRIMARY_ZONE_AUDIO_ATTRIBUTES_0)
694                          .setAudioDeviceAttributes(List.of(
695                                  new AudioDeviceAttributes(mNotificationOutpuBus),
696                                  new AudioDeviceAttributes(mMediaOutputDevice)))
697                          .setMinActivationVolumeGainIndex(0)
698                          .setMaxActivationVolumeGainIndex(MAX_GAIN / STEP_SIZE).build();
699          mTestPrimaryZoneVolumeInfo1 =
700                  new CarVolumeGroupInfo.Builder("config 0 group " + TEST_PRIMARY_ZONE_GROUP_1,
701                          PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_1).setMuted(true)
702                          .setMinVolumeGainIndex(0).setMaxVolumeGainIndex(MAX_GAIN / STEP_SIZE)
703                          .setAudioAttributes(TEST_PRIMARY_ZONE_AUDIO_ATTRIBUTES_1)
704                          .setVolumeGainIndex(DEFAULT_GAIN / STEP_SIZE)
705                          .setAudioDeviceAttributes(List.of(
706                                  new AudioDeviceAttributes(mVoiceOutpuBus),
707                                  new AudioDeviceAttributes(mNavOutputDevice)))
708                          .setMinActivationVolumeGainIndex(0)
709                          .setMaxActivationVolumeGainIndex(MAX_GAIN / STEP_SIZE).build();
710          mTestSecondaryConfig0VolumeGroup0Info =
711                  new CarVolumeGroupInfo.Builder("config 0 group " + TEST_SECONDARY_ZONE_GROUP_0,
712                          TEST_REAR_LEFT_ZONE_ID, TEST_SECONDARY_ZONE_GROUP_0)
713                          .setMinVolumeGainIndex(0).setMaxVolumeGainIndex(MAX_GAIN / STEP_SIZE)
714                          .setAudioAttributes(TEST_SECONDARY_ZONE_AUDIO_ATTRIBUTES_DEFAULT)
715                          .setVolumeGainIndex(DEFAULT_GAIN / STEP_SIZE)
716                          .setAudioDeviceAttributes(List.of(
717                                  new AudioDeviceAttributes(mSecondaryConfig0Group0Device)))
718                          .setMinActivationVolumeGainIndex(0)
719                          .setMaxActivationVolumeGainIndex(MAX_GAIN / STEP_SIZE).build();
720          mTestSecondaryZoneConfig1VolumeInfo0 =
721                  new CarVolumeGroupInfo.Builder("config 1 group " + TEST_SECONDARY_ZONE_GROUP_0,
722                          TEST_REAR_LEFT_ZONE_ID, TEST_SECONDARY_ZONE_GROUP_0)
723                          .setMinVolumeGainIndex(0).setMaxVolumeGainIndex(MAX_GAIN / STEP_SIZE)
724                          .setAudioAttributes(TEST_SECONDARY_ZONE_AUDIO_ATTRIBUTES_0)
725                          .setVolumeGainIndex(DEFAULT_GAIN / STEP_SIZE)
726                          .setAudioDeviceAttributes(List.of(new AudioDeviceAttributes(
727                                  mSecondaryConfig1Group0Device)))
728                          .setMinActivationVolumeGainIndex(0)
729                          .setMaxActivationVolumeGainIndex(MAX_GAIN / STEP_SIZE).build();
730          mTestSecondaryZoneConfig1VolumeInfo1 =
731                  new CarVolumeGroupInfo.Builder("config 1 group " + TEST_SECONDARY_ZONE_GROUP_1,
732                          TEST_REAR_LEFT_ZONE_ID, TEST_SECONDARY_ZONE_GROUP_1)
733                          .setMinVolumeGainIndex(0).setMaxVolumeGainIndex(MAX_GAIN / STEP_SIZE)
734                          .setAudioAttributes(TEST_SECONDARY_ZONE_AUDIO_ATTRIBUTES_1)
735                          .setVolumeGainIndex(DEFAULT_GAIN / STEP_SIZE)
736                          .setAudioDeviceAttributes(List.of(new AudioDeviceAttributes(
737                                  mSecondaryConfig1Group1Device)))
738                          .setMinActivationVolumeGainIndex(0)
739                          .setMaxActivationVolumeGainIndex(MAX_GAIN / STEP_SIZE).build();
740          mTestCarVolumeGroupEvent =
741                  new CarVolumeGroupEvent.Builder(List.of(mTestPrimaryZoneUmMutedVolueInfo0),
742                          CarVolumeGroupEvent.EVENT_TYPE_VOLUME_GAIN_INDEX_CHANGED,
743                          List.of(CarVolumeGroupEvent.EXTRA_INFO_VOLUME_INDEX_CHANGED_BY_UI)).build();
744          mTestCarMuteGroupEvent =
745                  new CarVolumeGroupEvent.Builder(List.of(mTestPrimaryZoneUmMutedVolueInfo0),
746                          CarVolumeGroupEvent.EVENT_TYPE_MUTE_CHANGED,
747                          List.of(CarVolumeGroupEvent.EXTRA_INFO_VOLUME_INDEX_CHANGED_BY_UI)).build();
748          mTestCarZoneReconfigurationEvent =
749                  new CarVolumeGroupEvent.Builder(List.of(mTestPrimaryZoneUmMutedVolueInfo0),
750                          CarVolumeGroupEvent.EVENT_TYPE_ZONE_CONFIGURATION_CHANGED,
751                          List.of(CarVolumeGroupEvent.EXTRA_INFO_VOLUME_INDEX_CHANGED_BY_UI)).build();
752          when(mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS))
753                  .thenReturn(outputDevices);
754          when(mAudioManager.getDevices(AudioManager.GET_DEVICES_INPUTS))
755                 .thenReturn(inputDevices);
756  
757          when(mAudioManager.registerAudioPolicy(any())).thenAnswer(invocation -> {
758              AudioPolicy policy = (AudioPolicy) invocation.getArguments()[0];
759              policy.setRegistration(REGISTRATION_ID);
760  
761              // Only return an specific result if testing failures at different phases.
762              return mAudioPolicyRegistrationStatus.isEmpty()
763                      ? SUCCESS : mAudioPolicyRegistrationStatus.get(mRegistrationCount++);
764          });
765  
766          when(mAudioManager.isAudioServerRunning()).thenReturn(true);
767  
768          // Needed by audio policy when setting UID device affinity
769          IBinder mockBinder = mock(IBinder.class);
770          when(mockBinder.queryLocalInterface(any())).thenReturn(mMockAudioService);
771          doReturn(mockBinder).when(() -> ServiceManager.getService(Context.AUDIO_SERVICE));
772      }
773  
setUpResources()774      private void setUpResources() {
775          when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver);
776          when(mMockContext.createContextAsUser(any(), anyInt())).thenReturn(mMockContext);
777          when(mMockContext.getResources()).thenReturn(mMockResources);
778          when(mMockResources.getBoolean(audioUseDynamicRouting)).thenReturn(mUseDynamicRouting);
779          when(mMockResources.getInteger(audioVolumeKeyEventTimeoutMs))
780                  .thenReturn(VOLUME_KEY_EVENT_TIMEOUT_MS);
781          when(mMockResources.getBoolean(audioUseHalDuckingSignals)).thenReturn(mUseHalAudioDucking);
782          when(mMockResources.getBoolean(audioUseCarVolumeGroupMuting))
783                  .thenReturn(mUseCarVolumeGroupMuting);
784          when(mMockResources.getBoolean(audioUseCarVolumeGroupEvent))
785                  .thenReturn(mUseCarVolumeGroupEvents);
786          when(mMockResources.getBoolean(audioUseMinMaxActivationVolume))
787                  .thenReturn(mUseMinMaxActivationVolume);
788          when(mMockResources.getInteger(audioVolumeAdjustmentContextsVersion))
789                  .thenReturn(AUDIO_CONTEXT_PRIORITY_LIST_VERSION_ONE);
790          when(mMockResources.getBoolean(audioPersistMasterMuteState)).thenReturn(mPersistMasterMute);
791          enableVolumeKeyEventsToDynamicDevices(mEnableVolumeKeyEventsToDynamicDevices);
792      }
793  
enableVolumeKeyEventsToDynamicDevices(boolean enableVolumeKeyEvents)794      private void enableVolumeKeyEventsToDynamicDevices(boolean enableVolumeKeyEvents) {
795          when(mMockResources.getBoolean(audioEnableVolumeKeyEventsToDynamicDevices))
796                  .thenReturn(enableVolumeKeyEvents);
797      }
798  
799      @Test
constructor_withValidContext()800      public void constructor_withValidContext() {
801          AudioManager manager = mock(AudioManager.class);
802          when(mMockContext.getSystemService(AudioManager.class)).thenReturn(manager);
803  
804          new CarAudioService(mMockContext);
805  
806          verify(mMockContext).getSystemService(AudioManager.class);
807          verify(mMockContext).getSystemService(TelephonyManager.class);
808      }
809  
810      @Test
constructor_withNullContext_fails()811      public void constructor_withNullContext_fails() {
812          NullPointerException thrown =
813                  assertThrows(NullPointerException.class, () -> new CarAudioService(null));
814  
815          expectWithMessage("Car Audio Service Construction Exception")
816                  .that(thrown).hasMessageThat().contains("Context");
817      }
818  
819      @Test
constructor_withNullContextAndNullPath_fails()820      public void constructor_withNullContextAndNullPath_fails() {
821          NullPointerException thrown =
822                  assertThrows(NullPointerException.class,
823                          () -> new CarAudioService(/* context= */null,
824                                  /* audioManagerWrapper= */ null,
825                                  /* audioConfigurationPath= */ null,
826                                  /* carVolumeCallbackHandler= */ null,
827                                  /* audioFadeConfigurationPath= */ null));
828  
829          expectWithMessage("Car Audio Service Construction")
830                  .that(thrown).hasMessageThat().contains("Context");
831      }
832  
833      @Test
constructor_withLegacyMode_enableFadeManagerConfiguration_fails()834      public void constructor_withLegacyMode_enableFadeManagerConfiguration_fails()
835              throws Exception {
836          mSetFlagsRule.enableFlags(FLAG_ENABLE_FADE_MANAGER_CONFIGURATION);
837          mSetFlagsRule.enableFlags(Flags.FLAG_CAR_AUDIO_FADE_MANAGER_CONFIGURATION);
838          when(mMockResources.getBoolean(audioUseDynamicRouting)).thenReturn(false);
839          when(mMockResources.getBoolean(audioUseFadeManagerConfiguration)).thenReturn(true);
840  
841          IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
842                  () -> setUpAudioServiceWithoutInit());
843  
844          expectWithMessage("Car audio service construction").that(thrown).hasMessageThat()
845                  .containsMatch("Fade manager configuration feature can not");
846      }
847  
848      @Test
init_withVolumeControlPolicyRegistrationError_fails()849      public void init_withVolumeControlPolicyRegistrationError_fails() throws Exception {
850          mAudioPolicyRegistrationStatus.add(ERROR);
851          CarAudioService service = setUpAudioServiceWithoutInit();
852  
853          IllegalStateException thrown =
854                  assertThrows(IllegalStateException.class, () -> service.init());
855  
856          expectWithMessage("Audio control policy registration exception").that(thrown)
857                  .hasMessageThat().containsMatch("car audio service's volume control audio policy");
858      }
859  
860      @Test
init_withRepeatedDynamicDevicesInConfig_fails()861      public void init_withRepeatedDynamicDevicesInConfig_fails() throws Exception {
862          setUpTempFileForAudioConfiguration(
863                  R.raw.car_audio_configuration_repeated_dynamic_devices_in_config);
864          setUpTempFileForAudioFadeConfiguration(R.raw.car_audio_fade_configuration);
865          CarAudioService service = setUpAudioServiceWithDynamicDevices(mTempCarAudioConfigFile,
866                  mTempCarAudioFadeConfigFile);
867  
868          RuntimeException thrown =
869                  assertThrows(RuntimeException.class, () -> service.init());
870  
871          expectWithMessage("Car audio zone config with multiple dynamic devices exception")
872                  .that(thrown).hasMessageThat()
873                  .containsMatch("Invalid zone configurations for zone");
874      }
875  
876      @Test
init_withFocusControlPolicyRegistrationError_fails()877      public void init_withFocusControlPolicyRegistrationError_fails() throws Exception {
878          mAudioPolicyRegistrationStatus.add(SUCCESS);
879          mAudioPolicyRegistrationStatus.add(ERROR);
880          CarAudioService service = setUpAudioServiceWithoutInit();
881  
882          IllegalStateException thrown =
883                  assertThrows(IllegalStateException.class, () -> service.init());
884  
885          expectWithMessage("Audio control policy registration exception").that(thrown)
886                  .hasMessageThat().containsMatch("car audio service's focus control audio policy");
887      }
888  
889      @Test
init_withAudioRoutingPolicyRegistrationError_fails()890      public void init_withAudioRoutingPolicyRegistrationError_fails() throws Exception {
891          mAudioPolicyRegistrationStatus.add(SUCCESS);
892          mAudioPolicyRegistrationStatus.add(SUCCESS);
893          mAudioPolicyRegistrationStatus.add(ERROR);
894          CarAudioService service = setUpAudioServiceWithoutInit();
895  
896          IllegalStateException thrown =
897                  assertThrows(IllegalStateException.class, () -> service.init());
898  
899          expectWithMessage("Audio routing policy registration exception").that(thrown)
900                  .hasMessageThat().containsMatch("Audio routing policy registration");
901      }
902  
903      @Test
init_withFadeManagerConfigPolicyRegistrationError_fails()904      public void init_withFadeManagerConfigPolicyRegistrationError_fails() throws Exception {
905          mSetFlagsRule.enableFlags(FLAG_ENABLE_FADE_MANAGER_CONFIGURATION);
906          mSetFlagsRule.enableFlags(Flags.FLAG_CAR_AUDIO_FADE_MANAGER_CONFIGURATION);
907          when(mMockResources.getBoolean(audioUseFadeManagerConfiguration)).thenReturn(true);
908          mAudioPolicyRegistrationStatus.add(SUCCESS);
909          mAudioPolicyRegistrationStatus.add(SUCCESS);
910          mAudioPolicyRegistrationStatus.add(SUCCESS);
911          mAudioPolicyRegistrationStatus.add(ERROR);
912          CarAudioService service = setUpAudioServiceWithoutInit();
913  
914          IllegalStateException thrown =
915                  assertThrows(IllegalStateException.class, () -> service.init());
916  
917          expectWithMessage("Audio fade policy registration exception").that(thrown).hasMessageThat()
918                  .containsMatch("car audio service's fade configuration audio policy");
919      }
920  
921      @Test
init_initializesAudioServiceCallbacks()922      public void init_initializesAudioServiceCallbacks() throws Exception {
923          mSetFlagsRule.disableFlags(Flags.FLAG_CAR_AUDIO_DYNAMIC_DEVICES);
924          CarAudioService service = setUpAudioServiceWithoutInit();
925  
926          service.init();
927  
928          verify(mAudioManager).setAudioServerStateCallback(any(), any());
929          verify(mAudioManager, never()).registerAudioDeviceCallback(any(), any());
930      }
931  
932      @Test
init_initializesAudioServiceCallbacks_withDynamicDevices()933      public void init_initializesAudioServiceCallbacks_withDynamicDevices() throws Exception {
934          mSetFlagsRule.enableFlags(Flags.FLAG_CAR_AUDIO_DYNAMIC_DEVICES);
935          CarAudioService service = setUpAudioServiceWithDynamicDevices();
936  
937          service.init();
938  
939          verify(mAudioManager).setAudioServerStateCallback(any(), any());
940          verify(mAudioManager).registerAudioDeviceCallback(any(), any());
941      }
942  
943      @Test
init_withDynamicDevices()944      public void init_withDynamicDevices() throws Exception {
945          mSetFlagsRule.enableFlags(Flags.FLAG_CAR_AUDIO_DYNAMIC_DEVICES);
946          CarAudioService audioServiceWithDynamicDevices = setUpAudioServiceWithDynamicDevices();
947  
948          audioServiceWithDynamicDevices.init();
949  
950          List<CarAudioZoneConfigInfo> zoneConfigInfos =
951                  audioServiceWithDynamicDevices.getAudioZoneConfigInfos(PRIMARY_AUDIO_ZONE);
952          List<String> names = zoneConfigInfos.stream().map(config -> config.getName()).toList();
953          expectWithMessage("Dynamic configuration names").that(names).containsExactly(
954                  DEFAULT_CONFIG_NAME_DYNAMIC_DEVICES, PRIMARY_CONFIG_NAME_DYNAMIC_DEVICES,
955                  TERTIARY_CONFIG_NAME_DYNAMIC_DEVICES);
956          CarAudioZoneConfigInfo btConfig = zoneConfigInfos.stream()
957                  .filter(config -> config.getName().equals(PRIMARY_CONFIG_NAME_DYNAMIC_DEVICES))
958                  .findFirst().orElseThrow();
959          expectWithMessage("Bluetooth configuration by default active status")
960                  .that(btConfig.isActive()).isFalse();
961      }
962  
963      @Test
init_withAudioServerDown()964      public void init_withAudioServerDown() throws Exception {
965          mSetFlagsRule.enableFlags(Flags.FLAG_CAR_AUDIO_DYNAMIC_DEVICES);
966          when(mAudioManager.isAudioServerRunning()).thenReturn(false);
967          CarAudioService service = setUpAudioServiceWithDynamicDevices();
968  
969          service.init();
970  
971          verify(mAudioManager).setAudioServerStateCallback(any(), any());
972          verify(mAudioManager, never()).registerAudioDeviceCallback(any(), any());
973      }
974  
975      @Test
release_releasesAudioServiceCallbacks()976      public void release_releasesAudioServiceCallbacks() throws Exception {
977          mSetFlagsRule.disableFlags(Flags.FLAG_CAR_AUDIO_DYNAMIC_DEVICES);
978          CarAudioService service = setUpAudioService();
979  
980          service.release();
981  
982          verify(mAudioManager, never()).unregisterAudioDeviceCallback(any());
983          verify(mAudioManager).clearAudioServerStateCallback();
984          verify(mAudioControlWrapperAidl).clearModuleChangeCallback();
985      }
986  
987      @Test
release_releasesAudioServiceCallbacks_withDynamicDevices()988      public void release_releasesAudioServiceCallbacks_withDynamicDevices() throws Exception {
989          CarAudioService service = setUpAudioServiceWithDynamicDevices();
990          service.init();
991  
992          service.release();
993  
994          verify(mAudioManager).unregisterAudioDeviceCallback(any());
995          verify(mAudioManager).clearAudioServerStateCallback();
996          verify(mAudioControlWrapperAidl).clearModuleChangeCallback();
997      }
998  
999      @Test
release_withoutModuleChangeCallback()1000      public void release_withoutModuleChangeCallback() throws Exception {
1001          when(mAudioControlWrapperAidl.supportsFeature(
1002                  AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_MODULE_CALLBACK)).thenReturn(false);
1003          CarAudioService service = setUpAudioService();
1004  
1005          service.release();
1006  
1007          verify(mAudioControlWrapperAidl, never()).clearModuleChangeCallback();
1008      }
1009  
1010      @Test
getAudioZoneIds_withBaseConfiguration_returnAllTheZones()1011      public void getAudioZoneIds_withBaseConfiguration_returnAllTheZones() throws Exception {
1012          CarAudioService service = setUpAudioService();
1013  
1014          expectWithMessage("Car Audio Service Zones")
1015                  .that(service.getAudioZoneIds()).asList()
1016                  .containsExactly(PRIMARY_AUDIO_ZONE, TEST_REAR_LEFT_ZONE_ID,
1017                          TEST_REAR_RIGHT_ZONE_ID, TEST_FRONT_ZONE_ID, TEST_REAR_ROW_3_ZONE_ID);
1018      }
1019  
1020      @Test
getVolumeGroupCount_onPrimaryZone_returnsAllGroups()1021      public void getVolumeGroupCount_onPrimaryZone_returnsAllGroups() throws Exception {
1022          CarAudioService service = setUpAudioService();
1023  
1024          expectWithMessage("Primary zone car volume group count")
1025                  .that(service.getVolumeGroupCount(PRIMARY_AUDIO_ZONE))
1026                  .isEqualTo(PRIMARY_ZONE_VOLUME_GROUP_COUNT);
1027      }
1028  
1029      @Test
getVolumeGroupCount_onPrimaryZone_withNonDynamicRouting_returnsAllGroups()1030      public void getVolumeGroupCount_onPrimaryZone_withNonDynamicRouting_returnsAllGroups()
1031              throws Exception {
1032          CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
1033  
1034          expectWithMessage("Non dynamic routing primary zone car volume group count")
1035                  .that(nonDynamicAudioService.getVolumeGroupCount(PRIMARY_AUDIO_ZONE))
1036                  .isEqualTo(CarAudioDynamicRouting.STREAM_TYPES.length);
1037      }
1038  
1039      @Test
getVolumeGroupIdForUsage_forMusicUsage()1040      public void getVolumeGroupIdForUsage_forMusicUsage() throws Exception {
1041          CarAudioService service = setUpAudioService();
1042  
1043          expectWithMessage("Primary zone's media car volume group id")
1044                  .that(service.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE, USAGE_MEDIA))
1045                  .isEqualTo(MEDIA_VOLUME_GROUP_ID);
1046      }
1047  
1048      @Test
getVolumeGroupIdForUsage_withNonDynamicRouting_forMusicUsage()1049      public void getVolumeGroupIdForUsage_withNonDynamicRouting_forMusicUsage() throws Exception {
1050          CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
1051  
1052          expectWithMessage("Non dynamic routing primary zone's media car volume group id")
1053                  .that(nonDynamicAudioService.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE,
1054                          USAGE_MEDIA)).isEqualTo(MEDIA_VOLUME_GROUP_ID);
1055      }
1056  
1057      @Test
getVolumeGroupIdForUsage_forNavigationUsage()1058      public void getVolumeGroupIdForUsage_forNavigationUsage() throws Exception {
1059          CarAudioService service = setUpAudioService();
1060  
1061          expectWithMessage("Primary zone's navigation car volume group id")
1062                  .that(service.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE,
1063                          USAGE_ASSISTANCE_NAVIGATION_GUIDANCE))
1064                  .isEqualTo(NAVIGATION_VOLUME_GROUP_ID);
1065      }
1066  
1067      @Test
getVolumeGroupIdForUsage_withNonDynamicRouting_forNavigationUsage()1068      public void getVolumeGroupIdForUsage_withNonDynamicRouting_forNavigationUsage()
1069              throws Exception {
1070          CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
1071  
1072          expectWithMessage("Non dynamic routing primary zone's navigation car volume group id")
1073                  .that(nonDynamicAudioService.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE,
1074                          USAGE_ASSISTANCE_NAVIGATION_GUIDANCE))
1075                  .isEqualTo(INVALID_VOLUME_GROUP_ID);
1076      }
1077  
1078      @Test
getVolumeGroupIdForUsage_forInvalidUsage_returnsInvalidGroupId()1079      public void getVolumeGroupIdForUsage_forInvalidUsage_returnsInvalidGroupId() throws Exception {
1080          CarAudioService service = setUpAudioService();
1081  
1082          expectWithMessage("Primary zone's invalid car volume group id")
1083                  .that(service.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE, INVALID_USAGE))
1084                  .isEqualTo(INVALID_VOLUME_GROUP_ID);
1085      }
1086  
1087      @Test
1088      public void
getVolumeGroupIdForUsage_forInvalidUsage_withNonDynamicRouting_returnsInvalidGroupId()1089              getVolumeGroupIdForUsage_forInvalidUsage_withNonDynamicRouting_returnsInvalidGroupId()
1090              throws Exception {
1091          CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
1092  
1093          expectWithMessage("Non dynamic routing primary zone's invalid car volume group id")
1094                  .that(nonDynamicAudioService.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE,
1095                          INVALID_USAGE)).isEqualTo(INVALID_VOLUME_GROUP_ID);
1096      }
1097  
1098      @Test
getVolumeGroupIdForUsage_forUnknownUsage_returnsMediaGroupId()1099      public void getVolumeGroupIdForUsage_forUnknownUsage_returnsMediaGroupId() throws Exception {
1100          CarAudioService service = setUpAudioService();
1101  
1102          expectWithMessage("Primary zone's unknown car volume group id")
1103                  .that(service.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE, USAGE_UNKNOWN))
1104                  .isEqualTo(MEDIA_VOLUME_GROUP_ID);
1105      }
1106  
1107      @Test
getVolumeGroupIdForUsage_forVirtualUsage_returnsInvalidGroupId()1108      public void getVolumeGroupIdForUsage_forVirtualUsage_returnsInvalidGroupId() throws Exception {
1109          CarAudioService service = setUpAudioService();
1110  
1111          expectWithMessage("Primary zone's virtual car volume group id")
1112                  .that(service.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE,
1113                          AudioManagerHelper.getUsageVirtualSource()))
1114                  .isEqualTo(INVALID_VOLUME_GROUP_ID);
1115      }
1116  
1117      @Test
getVolumeGroupCount_onSecondaryZone_returnsAllGroups()1118      public void getVolumeGroupCount_onSecondaryZone_returnsAllGroups() throws Exception {
1119          CarAudioService service = setUpAudioService();
1120  
1121          expectWithMessage("Secondary Zone car volume group count")
1122                  .that(service.getVolumeGroupCount(TEST_REAR_LEFT_ZONE_ID))
1123                  .isEqualTo(SECONDARY_ZONE_VOLUME_GROUP_COUNT);
1124      }
1125  
1126      @Test
getUsagesForVolumeGroupId_forMusicContext()1127      public void getUsagesForVolumeGroupId_forMusicContext() throws Exception {
1128          CarAudioService service = setUpAudioService();
1129  
1130  
1131          expectWithMessage("Primary zone's music car volume group id usages")
1132                  .that(service.getUsagesForVolumeGroupId(PRIMARY_AUDIO_ZONE,
1133                          MEDIA_VOLUME_GROUP_ID)).asList()
1134                  .containsExactly(USAGE_UNKNOWN, USAGE_GAME, USAGE_MEDIA, USAGE_ANNOUNCEMENT,
1135                          USAGE_NOTIFICATION, USAGE_NOTIFICATION_EVENT);
1136      }
1137  
1138      @Test
getUsagesForVolumeGroupId_forSystemContext()1139      public void getUsagesForVolumeGroupId_forSystemContext() throws Exception {
1140          CarAudioService service = setUpAudioService();
1141          int systemVolumeGroup =
1142                  service.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE, USAGE_EMERGENCY);
1143  
1144          expectWithMessage("Primary zone's system car volume group id usages")
1145                  .that(service.getUsagesForVolumeGroupId(PRIMARY_AUDIO_ZONE,
1146                          systemVolumeGroup)).asList().containsExactly(USAGE_ALARM, USAGE_EMERGENCY,
1147                          USAGE_SAFETY, USAGE_VEHICLE_STATUS, USAGE_ASSISTANCE_SONIFICATION);
1148      }
1149  
1150      @Test
getUsagesForVolumeGroupId_onSecondaryZone_forSingleVolumeGroupId_returnAllUsages()1151      public void getUsagesForVolumeGroupId_onSecondaryZone_forSingleVolumeGroupId_returnAllUsages()
1152              throws Exception {
1153          CarAudioService service = setUpAudioService();
1154  
1155          expectWithMessage("Secondary Zone's car volume group id usages")
1156                  .that(service.getUsagesForVolumeGroupId(TEST_REAR_LEFT_ZONE_ID,
1157                          SECONDARY_ZONE_VOLUME_GROUP_ID))
1158                  .asList().containsExactly(USAGE_UNKNOWN, USAGE_MEDIA,
1159                          USAGE_VOICE_COMMUNICATION, USAGE_VOICE_COMMUNICATION_SIGNALLING,
1160                          USAGE_ALARM, USAGE_NOTIFICATION, USAGE_NOTIFICATION_RINGTONE,
1161                          USAGE_NOTIFICATION_EVENT, USAGE_ASSISTANCE_ACCESSIBILITY,
1162                          USAGE_ASSISTANCE_NAVIGATION_GUIDANCE, USAGE_ASSISTANCE_SONIFICATION,
1163                          USAGE_GAME, USAGE_ASSISTANT, USAGE_CALL_ASSISTANT, USAGE_EMERGENCY,
1164                          USAGE_ANNOUNCEMENT, USAGE_SAFETY, USAGE_VEHICLE_STATUS);
1165      }
1166  
1167      @Test
getUsagesForVolumeGroupId_withoutDynamicRouting()1168      public void getUsagesForVolumeGroupId_withoutDynamicRouting() throws Exception {
1169          CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
1170  
1171          expectWithMessage("Media car volume group id without dynamic routing").that(
1172                  nonDynamicAudioService.getUsagesForVolumeGroupId(PRIMARY_AUDIO_ZONE,
1173                  MEDIA_VOLUME_GROUP_ID)).asList()
1174                  .containsExactly(CarAudioDynamicRouting.STREAM_TYPE_USAGES[MEDIA_VOLUME_GROUP_ID]);
1175      }
1176  
1177      @Test
createAudioPatch_onMediaOutputDevice_failsForConfigurationMissing()1178      public void createAudioPatch_onMediaOutputDevice_failsForConfigurationMissing()
1179              throws Exception {
1180          CarAudioService service = setUpAudioService();
1181  
1182          doReturn(false)
1183                  .when(() -> SystemProperties.getBoolean(PROPERTY_RO_ENABLE_AUDIO_PATCH, false));
1184  
1185          IllegalStateException thrown = assertThrows(IllegalStateException.class, () ->
1186                  service.createAudioPatch(PRIMARY_ZONE_FM_TUNER_ADDRESS, USAGE_MEDIA, DEFAULT_GAIN));
1187  
1188          expectWithMessage("FM and Media Audio Patch Exception")
1189                  .that(thrown).hasMessageThat().contains("Audio Patch APIs not enabled");
1190      }
1191  
1192      @Test
createAudioPatch_onMediaOutputDevice_failsForMissingPermission()1193      public void createAudioPatch_onMediaOutputDevice_failsForMissingPermission() throws Exception {
1194          CarAudioService service = setUpAudioService();
1195  
1196          mockDenyCarControlAudioSettingsPermission();
1197  
1198          SecurityException thrown = assertThrows(SecurityException.class,
1199                  () -> service
1200                          .createAudioPatch(PRIMARY_ZONE_FM_TUNER_ADDRESS,
1201                                  USAGE_MEDIA, DEFAULT_GAIN));
1202  
1203          expectWithMessage("FM and Media Audio Patch Permission Exception")
1204                  .that(thrown).hasMessageThat().contains(PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
1205      }
1206  
1207      @Test
createAudioPatch_onMediaOutputDevice_succeeds()1208      public void createAudioPatch_onMediaOutputDevice_succeeds() throws Exception {
1209          CarAudioService service = setUpAudioService();
1210  
1211          mockGrantCarControlAudioSettingsPermission();
1212          doReturn(false)
1213                  .when(() -> SystemProperties.getBoolean(PROPERTY_RO_ENABLE_AUDIO_PATCH, true));
1214          doReturn(new AudioPatchInfo(PRIMARY_ZONE_FM_TUNER_ADDRESS, MEDIA_TEST_DEVICE, 0))
1215                  .when(() -> AudioManagerHelper
1216                          .createAudioPatch(mFmTunerInputDevice, mMediaOutputDevice, DEFAULT_GAIN));
1217  
1218          CarAudioPatchHandle audioPatch = service
1219                  .createAudioPatch(PRIMARY_ZONE_FM_TUNER_ADDRESS, USAGE_MEDIA, DEFAULT_GAIN);
1220  
1221          expectWithMessage("Audio Patch Sink Address")
1222                  .that(audioPatch.getSinkAddress()).isEqualTo(MEDIA_TEST_DEVICE);
1223          expectWithMessage("Audio Patch Source Address")
1224                  .that(audioPatch.getSourceAddress()).isEqualTo(PRIMARY_ZONE_FM_TUNER_ADDRESS);
1225          expectWithMessage("Audio Patch Handle")
1226                  .that(audioPatch.getHandleId()).isEqualTo(0);
1227      }
1228  
1229      @Test
releaseAudioPatch_failsForConfigurationMissing()1230      public void releaseAudioPatch_failsForConfigurationMissing() throws Exception {
1231          CarAudioService service = setUpAudioService();
1232  
1233          doReturn(false)
1234                  .when(() -> SystemProperties.getBoolean(PROPERTY_RO_ENABLE_AUDIO_PATCH, false));
1235          CarAudioPatchHandle carAudioPatchHandle =
1236                  new CarAudioPatchHandle(0, PRIMARY_ZONE_FM_TUNER_ADDRESS, MEDIA_TEST_DEVICE);
1237  
1238          IllegalStateException thrown = assertThrows(IllegalStateException.class,
1239                  () -> service.releaseAudioPatch(carAudioPatchHandle));
1240  
1241          expectWithMessage("Release FM and Media Audio Patch Exception")
1242                  .that(thrown).hasMessageThat().contains("Audio Patch APIs not enabled");
1243      }
1244  
1245      @Test
releaseAudioPatch_failsForMissingPermission()1246      public void releaseAudioPatch_failsForMissingPermission() throws Exception {
1247          CarAudioService service = setUpAudioService();
1248  
1249          mockDenyCarControlAudioSettingsPermission();
1250          CarAudioPatchHandle carAudioPatchHandle =
1251                  new CarAudioPatchHandle(0, PRIMARY_ZONE_FM_TUNER_ADDRESS, MEDIA_TEST_DEVICE);
1252  
1253          SecurityException thrown = assertThrows(SecurityException.class,
1254                  () -> service.releaseAudioPatch(carAudioPatchHandle));
1255  
1256          expectWithMessage("FM and Media Audio Patch Permission Exception")
1257                  .that(thrown).hasMessageThat().contains(PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
1258      }
1259  
1260      @Test
releaseAudioPatch_forNullSourceAddress_throwsNullPointerException()1261      public void releaseAudioPatch_forNullSourceAddress_throwsNullPointerException()
1262              throws Exception {
1263          CarAudioService service = setUpAudioService();
1264          mockGrantCarControlAudioSettingsPermission();
1265          doReturn(new AudioPatchInfo(PRIMARY_ZONE_FM_TUNER_ADDRESS, MEDIA_TEST_DEVICE, 0))
1266                  .when(() -> AudioManagerHelper
1267                          .createAudioPatch(mFmTunerInputDevice, mMediaOutputDevice, DEFAULT_GAIN));
1268  
1269          CarAudioPatchHandle audioPatch = mock(CarAudioPatchHandle.class);
1270          when(audioPatch.getSourceAddress()).thenReturn(null);
1271  
1272          NullPointerException thrown = assertThrows(NullPointerException.class,
1273                  () -> service.releaseAudioPatch(audioPatch));
1274  
1275          expectWithMessage("Release audio patch for null source address "
1276                  + "and sink address Null Exception")
1277                  .that(thrown).hasMessageThat()
1278                  .contains("Source Address can not be null for patch id 0");
1279      }
1280  
1281      @Test
releaseAudioPatch_failsForNullPatch()1282      public void releaseAudioPatch_failsForNullPatch() throws Exception {
1283          CarAudioService service = setUpAudioService();
1284  
1285          assertThrows(NullPointerException.class,
1286                  () -> service.releaseAudioPatch(null));
1287      }
1288  
1289      @Test
setZoneIdForUid_withoutRoutingPermission_fails()1290      public void setZoneIdForUid_withoutRoutingPermission_fails() throws Exception {
1291          CarAudioService service = setUpAudioService();
1292  
1293          mockDenyCarControlAudioSettingsPermission();
1294  
1295          SecurityException thrown = assertThrows(SecurityException.class,
1296                  () -> service.setZoneIdForUid(OUT_OF_RANGE_ZONE, MEDIA_APP_UID));
1297  
1298          expectWithMessage("Set Zone for UID Permission Exception")
1299                  .that(thrown).hasMessageThat()
1300                  .contains(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
1301      }
1302  
1303      @Test
setZoneIdForUid_withoutDynamicRouting_fails()1304      public void setZoneIdForUid_withoutDynamicRouting_fails() throws Exception {
1305          CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
1306  
1307          IllegalStateException thrown = assertThrows(IllegalStateException.class,
1308                  () -> nonDynamicAudioService.setZoneIdForUid(PRIMARY_AUDIO_ZONE, MEDIA_APP_UID));
1309  
1310          expectWithMessage("Set Zone for UID Dynamic Configuration Exception")
1311                  .that(thrown).hasMessageThat()
1312                  .contains("Non legacy routing is required");
1313      }
1314  
1315      @Test
setZoneIdForUid_withInvalidZone_fails()1316      public void setZoneIdForUid_withInvalidZone_fails() throws Exception {
1317          CarAudioService service = setUpAudioService();
1318  
1319          IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
1320                  () -> service.setZoneIdForUid(INVALID_AUDIO_ZONE, MEDIA_APP_UID));
1321  
1322          expectWithMessage("Set Zone for UID Invalid Zone Exception")
1323                  .that(thrown).hasMessageThat()
1324                  .contains("Invalid audio zone Id " + INVALID_AUDIO_ZONE);
1325      }
1326  
1327      @Test
setZoneIdForUid_withOutOfRangeZone_fails()1328      public void setZoneIdForUid_withOutOfRangeZone_fails() throws Exception {
1329          CarAudioService service = setUpAudioService();
1330  
1331          IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
1332                  () -> service.setZoneIdForUid(OUT_OF_RANGE_ZONE, MEDIA_APP_UID));
1333  
1334          expectWithMessage("Set Zone for UID Zone Out of Range Exception")
1335                  .that(thrown).hasMessageThat()
1336                  .contains("Invalid audio zone Id " + OUT_OF_RANGE_ZONE);
1337      }
1338  
1339      @Test
setZoneIdForUid_withZoneAudioMapping_fails()1340      public void setZoneIdForUid_withZoneAudioMapping_fails() throws Exception {
1341          CarAudioService service = setUpAudioService();
1342  
1343          IllegalStateException thrown = assertThrows(IllegalStateException.class,
1344                  () -> service.setZoneIdForUid(PRIMARY_AUDIO_ZONE, MEDIA_APP_UID));
1345  
1346          expectWithMessage("Set Zone for UID With Audio Zone Mapping Exception")
1347                  .that(thrown).hasMessageThat()
1348                  .contains("UID based routing is not supported while using occupant zone mapping");
1349      }
1350  
1351      @Test
setZoneIdForUid_withValidZone_succeeds()1352      public void setZoneIdForUid_withValidZone_succeeds() throws Exception {
1353          CarAudioService noZoneMappingAudioService = setUpCarAudioServiceWithoutZoneMapping();
1354  
1355          boolean results = noZoneMappingAudioService
1356                  .setZoneIdForUid(TEST_REAR_LEFT_ZONE_ID, MEDIA_APP_UID);
1357  
1358          expectWithMessage("Set Zone for UID Status").that(results).isTrue();
1359      }
1360  
1361      @Test
setZoneIdForUid_onDifferentZones_succeeds()1362      public void setZoneIdForUid_onDifferentZones_succeeds() throws Exception {
1363          CarAudioService noZoneMappingAudioService = setUpCarAudioServiceWithoutZoneMapping();
1364  
1365          noZoneMappingAudioService
1366                  .setZoneIdForUid(TEST_REAR_LEFT_ZONE_ID, MEDIA_APP_UID);
1367  
1368          boolean results = noZoneMappingAudioService
1369                  .setZoneIdForUid(PRIMARY_AUDIO_ZONE, MEDIA_APP_UID);
1370  
1371          expectWithMessage("Set Zone for UID For Different Zone")
1372                  .that(results).isTrue();
1373      }
1374  
1375      @Test
setZoneIdForUid_onDifferentZones_withAudioFocus_succeeds()1376      public void setZoneIdForUid_onDifferentZones_withAudioFocus_succeeds() throws Exception {
1377          CarAudioService noZoneMappingAudioService = setUpCarAudioServiceWithoutZoneMapping();
1378          AudioFocusInfo audioFocusInfo = createAudioFocusInfoForMedia();
1379  
1380          noZoneMappingAudioService
1381                  .setZoneIdForUid(TEST_REAR_LEFT_ZONE_ID, MEDIA_APP_UID);
1382  
1383          noZoneMappingAudioService
1384                  .requestAudioFocusForTest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
1385  
1386          boolean results = noZoneMappingAudioService
1387                  .setZoneIdForUid(PRIMARY_AUDIO_ZONE, MEDIA_APP_UID);
1388  
1389          expectWithMessage("Set Zone for UID For Different Zone with Audio Focus")
1390                  .that(results).isTrue();
1391      }
1392  
1393      @Test
getZoneIdForUid_withoutMappedUid_succeeds()1394      public void getZoneIdForUid_withoutMappedUid_succeeds() throws Exception {
1395          CarAudioService noZoneMappingAudioService = setUpCarAudioServiceWithoutZoneMapping();
1396  
1397          int zoneId = noZoneMappingAudioService
1398                  .getZoneIdForUid(MEDIA_APP_UID);
1399  
1400          expectWithMessage("Get Zone for Non Mapped UID")
1401                  .that(zoneId).isEqualTo(PRIMARY_AUDIO_ZONE);
1402      }
1403  
1404      @Test
getZoneIdForUid_succeeds()1405      public void getZoneIdForUid_succeeds() throws Exception {
1406          CarAudioService noZoneMappingAudioService = setUpCarAudioServiceWithoutZoneMapping();
1407  
1408          noZoneMappingAudioService
1409                  .setZoneIdForUid(TEST_REAR_LEFT_ZONE_ID, MEDIA_APP_UID);
1410  
1411          int zoneId = noZoneMappingAudioService
1412                  .getZoneIdForUid(MEDIA_APP_UID);
1413  
1414          expectWithMessage("Get Zone for UID Zone Id")
1415                  .that(zoneId).isEqualTo(TEST_REAR_LEFT_ZONE_ID);
1416      }
1417  
1418      @Test
getZoneIdForUid_afterSwitchingZones_succeeds()1419      public void getZoneIdForUid_afterSwitchingZones_succeeds() throws Exception {
1420          CarAudioService noZoneMappingAudioService = setUpCarAudioServiceWithoutZoneMapping();
1421  
1422          noZoneMappingAudioService
1423                  .setZoneIdForUid(TEST_REAR_LEFT_ZONE_ID, MEDIA_APP_UID);
1424  
1425          noZoneMappingAudioService
1426                  .setZoneIdForUid(PRIMARY_AUDIO_ZONE, MEDIA_APP_UID);
1427  
1428          int zoneId = noZoneMappingAudioService
1429                  .getZoneIdForUid(MEDIA_APP_UID);
1430  
1431          expectWithMessage("Get Zone for UID Zone Id")
1432                  .that(zoneId).isEqualTo(PRIMARY_AUDIO_ZONE);
1433      }
1434  
1435      @Test
clearZoneIdForUid_withoutRoutingPermission_fails()1436      public void clearZoneIdForUid_withoutRoutingPermission_fails() throws Exception {
1437          CarAudioService service = setUpAudioService();
1438  
1439          mockDenyCarControlAudioSettingsPermission();
1440  
1441          SecurityException thrown = assertThrows(SecurityException.class,
1442                  () -> service.clearZoneIdForUid(MEDIA_APP_UID));
1443  
1444          expectWithMessage("Clear Zone for UID Permission Exception")
1445                  .that(thrown).hasMessageThat()
1446                  .contains(Car.PERMISSION_CAR_CONTROL_AUDIO_SETTINGS);
1447      }
1448  
1449      @Test
clearZoneIdForUid_withoutDynamicRouting_fails()1450      public void clearZoneIdForUid_withoutDynamicRouting_fails() throws Exception {
1451          CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
1452  
1453          IllegalStateException thrown = assertThrows(IllegalStateException.class,
1454                  () -> nonDynamicAudioService.clearZoneIdForUid(MEDIA_APP_UID));
1455  
1456          expectWithMessage("Clear Zone for UID Dynamic Configuration Exception")
1457                  .that(thrown).hasMessageThat()
1458                  .contains("Non legacy routing is required");
1459      }
1460  
1461      @Test
clearZoneIdForUid_withZoneAudioMapping_fails()1462      public void clearZoneIdForUid_withZoneAudioMapping_fails() throws Exception {
1463          CarAudioService service = setUpAudioService();
1464  
1465          IllegalStateException thrown = assertThrows(IllegalStateException.class,
1466                  () -> service.clearZoneIdForUid(MEDIA_APP_UID));
1467  
1468          expectWithMessage("Clear Zone for UID Audio Zone Mapping Exception")
1469                  .that(thrown).hasMessageThat()
1470                  .contains("UID based routing is not supported while using occupant zone mapping");
1471      }
1472  
1473      @Test
clearZoneIdForUid_forNonMappedUid_succeeds()1474      public void clearZoneIdForUid_forNonMappedUid_succeeds() throws Exception {
1475          CarAudioService noZoneMappingAudioService = setUpCarAudioServiceWithoutZoneMapping();
1476  
1477          boolean status = noZoneMappingAudioService
1478                  .clearZoneIdForUid(MEDIA_APP_UID);
1479  
1480          expectWithMessage("Clear Zone for UID Audio Zone without Mapping")
1481                  .that(status).isTrue();
1482      }
1483  
1484      @Test
clearZoneIdForUid_forMappedUid_succeeds()1485      public void clearZoneIdForUid_forMappedUid_succeeds() throws Exception {
1486          CarAudioService noZoneMappingAudioService = setUpCarAudioServiceWithoutZoneMapping();
1487  
1488          noZoneMappingAudioService
1489                  .setZoneIdForUid(TEST_REAR_LEFT_ZONE_ID, MEDIA_APP_UID);
1490  
1491          boolean status = noZoneMappingAudioService.clearZoneIdForUid(MEDIA_APP_UID);
1492  
1493          expectWithMessage("Clear Zone for UID Audio Zone with Mapping")
1494                  .that(status).isTrue();
1495      }
1496  
1497      @Test
getZoneIdForUid_afterClearedUidMapping_returnsDefaultZone()1498      public void getZoneIdForUid_afterClearedUidMapping_returnsDefaultZone() throws Exception {
1499          CarAudioService noZoneMappingAudioService = setUpCarAudioServiceWithoutZoneMapping();
1500  
1501          noZoneMappingAudioService
1502                  .setZoneIdForUid(TEST_REAR_LEFT_ZONE_ID, MEDIA_APP_UID);
1503  
1504          noZoneMappingAudioService.clearZoneIdForUid(MEDIA_APP_UID);
1505  
1506          int zoneId = noZoneMappingAudioService.getZoneIdForUid(MEDIA_APP_UID);
1507  
1508          expectWithMessage("Get Zone for UID Audio Zone with Cleared Mapping")
1509                  .that(zoneId).isEqualTo(PRIMARY_AUDIO_ZONE);
1510      }
1511  
1512      @Test
getZoneIdForAudioFocusInfo_withoutMappedUid_succeeds()1513      public void getZoneIdForAudioFocusInfo_withoutMappedUid_succeeds() throws Exception {
1514          CarAudioService noZoneMappingAudioService = setUpCarAudioServiceWithoutZoneMapping();
1515  
1516          int zoneId = noZoneMappingAudioService
1517                  .getZoneIdForAudioFocusInfo(TEST_AUDIO_FOCUS_INFO);
1518  
1519          expectWithMessage("Mapped audio focus info's zone")
1520                  .that(zoneId).isEqualTo(PRIMARY_AUDIO_ZONE);
1521      }
1522  
1523      @Test
getZoneIdForAudioFocusInfo_succeeds()1524      public void getZoneIdForAudioFocusInfo_succeeds() throws Exception {
1525          CarAudioService noZoneMappingAudioService = setUpCarAudioServiceWithoutZoneMapping();
1526  
1527          noZoneMappingAudioService
1528                  .setZoneIdForUid(TEST_REAR_LEFT_ZONE_ID, MEDIA_APP_UID);
1529  
1530          int zoneId = noZoneMappingAudioService
1531                  .getZoneIdForAudioFocusInfo(TEST_AUDIO_FOCUS_INFO);
1532  
1533          expectWithMessage("Mapped audio focus info's zone")
1534                  .that(zoneId).isEqualTo(TEST_REAR_LEFT_ZONE_ID);
1535      }
1536  
1537      @Test
getZoneIdForAudioFocusInfo_afterSwitchingZones_succeeds()1538      public void getZoneIdForAudioFocusInfo_afterSwitchingZones_succeeds() throws Exception {
1539          CarAudioService noZoneMappingAudioService = setUpCarAudioServiceWithoutZoneMapping();
1540          noZoneMappingAudioService
1541                  .setZoneIdForUid(TEST_REAR_LEFT_ZONE_ID, MEDIA_APP_UID);
1542          noZoneMappingAudioService
1543                  .setZoneIdForUid(PRIMARY_AUDIO_ZONE, MEDIA_APP_UID);
1544  
1545          int zoneId = noZoneMappingAudioService
1546                  .getZoneIdForAudioFocusInfo(TEST_AUDIO_FOCUS_INFO);
1547  
1548          expectWithMessage("Remapped audio focus info's zone")
1549                  .that(zoneId).isEqualTo(PRIMARY_AUDIO_ZONE);
1550      }
1551  
1552      @Test
setGroupVolume_withoutPermission_fails()1553      public void setGroupVolume_withoutPermission_fails() throws Exception {
1554          CarAudioService service = setUpAudioService();
1555  
1556          mockDenyCarControlAudioVolumePermission();
1557  
1558          SecurityException thrown = assertThrows(SecurityException.class,
1559                  () -> service.setGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
1560                          TEST_GAIN_INDEX, TEST_FLAGS));
1561  
1562          expectWithMessage("Set Volume Group Permission Exception")
1563                  .that(thrown).hasMessageThat()
1564                  .contains(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME);
1565      }
1566  
1567      @Test
setGroupVolume_withDynamicRoutingDisabled()1568      public void setGroupVolume_withDynamicRoutingDisabled() throws Exception {
1569          CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
1570  
1571          nonDynamicAudioService.setGroupVolume(
1572                  PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0, TEST_GAIN_INDEX, TEST_FLAGS);
1573  
1574          verify(mAudioManager).setStreamVolume(
1575                  CarAudioDynamicRouting.STREAM_TYPES[TEST_PRIMARY_ZONE_GROUP_0],
1576                  TEST_GAIN_INDEX,
1577                  TEST_FLAGS);
1578      }
1579  
1580      @Test
setGroupVolume_verifyNoCallbacks()1581      public void setGroupVolume_verifyNoCallbacks() throws Exception {
1582          CarAudioService service = setUpAudioService();
1583          service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
1584                  /* mute= */ false, TEST_FLAGS);
1585          reset(mCarVolumeCallbackHandler);
1586  
1587          service.setGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
1588                  TEST_GAIN_INDEX, TEST_FLAGS);
1589  
1590          verify(mCarVolumeCallbackHandler, never()).onGroupMuteChange(anyInt(), anyInt(), anyInt());
1591      }
1592  
1593      @Test
setGroupVolume_afterSetVolumeGroupMute()1594      public void setGroupVolume_afterSetVolumeGroupMute() throws Exception {
1595          CarAudioService service = setUpAudioService();
1596          service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
1597                  /* mute= */ true, TEST_FLAGS);
1598          reset(mCarVolumeCallbackHandler);
1599  
1600          service.setGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
1601                  TEST_GAIN_INDEX, TEST_FLAGS);
1602  
1603          verify(mCarVolumeCallbackHandler).onGroupMuteChange(PRIMARY_AUDIO_ZONE,
1604                  TEST_PRIMARY_ZONE_GROUP_0, TEST_FLAGS);
1605      }
1606  
1607      @Test
setGroupVolume_withVolumeGroupMutingDisabled_doesnotThrowException()1608      public void setGroupVolume_withVolumeGroupMutingDisabled_doesnotThrowException()
1609              throws Exception {
1610          CarAudioService nonVolumeGroupMutingAudioService =
1611                  setUpAudioServiceWithDisabledResource(audioUseCarVolumeGroupMuting);
1612          HalAudioGainCallback callback = getHalAudioGainCallback();
1613          CarAudioGainConfigInfo carGain = createCarAudioGainConfigInfo(PRIMARY_AUDIO_ZONE,
1614                  MEDIA_TEST_DEVICE, TEST_GAIN_INDEX);
1615          callback.onAudioDeviceGainsChanged(List.of(Reasons.TCU_MUTE), List.of(carGain));
1616          reset(mCarVolumeCallbackHandler);
1617  
1618          nonVolumeGroupMutingAudioService.setGroupVolume(
1619                  PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0, TEST_GAIN_INDEX, TEST_FLAGS);
1620  
1621          // if an exception is thrown, the test automatically fails
1622          verify(mCarVolumeCallbackHandler).onVolumeGroupChange(eq(PRIMARY_AUDIO_ZONE),
1623                  eq(TEST_PRIMARY_ZONE_GROUP_0), anyInt());
1624          verify(mCarVolumeCallbackHandler, never()).onGroupMuteChange(anyInt(), anyInt(), anyInt());
1625      }
1626  
1627      @Test
getOutputDeviceAddressForUsage_forMusicUsage()1628      public void getOutputDeviceAddressForUsage_forMusicUsage() throws Exception {
1629          CarAudioService service = setUpAudioService();
1630  
1631          String mediaDeviceAddress =
1632                  service.getOutputDeviceAddressForUsage(PRIMARY_AUDIO_ZONE, USAGE_MEDIA);
1633  
1634          expectWithMessage("Media usage audio device address")
1635                  .that(mediaDeviceAddress).isEqualTo(MEDIA_TEST_DEVICE);
1636      }
1637  
1638      @Test
getOutputDeviceAddressForUsage_withNonDynamicRouting_forMediaUsage_fails()1639      public void getOutputDeviceAddressForUsage_withNonDynamicRouting_forMediaUsage_fails()
1640              throws Exception {
1641          when(mMockResources.getBoolean(audioUseCoreRouting)).thenReturn(false);
1642          CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
1643  
1644          IllegalStateException thrown = assertThrows(IllegalStateException.class,
1645                  () -> nonDynamicAudioService
1646                          .getOutputDeviceAddressForUsage(PRIMARY_AUDIO_ZONE, USAGE_MEDIA));
1647  
1648          expectWithMessage("Non dynamic routing media usage audio device address exception")
1649                  .that(thrown).hasMessageThat().contains("Non legacy routing is required");
1650      }
1651  
1652      @Test
getOutputDeviceAddressForUsage_forNavigationUsage()1653      public void getOutputDeviceAddressForUsage_forNavigationUsage() throws Exception {
1654          CarAudioService service = setUpAudioService();
1655  
1656          String mediaDeviceAddress =
1657                  service.getOutputDeviceAddressForUsage(PRIMARY_AUDIO_ZONE,
1658                          USAGE_ASSISTANCE_NAVIGATION_GUIDANCE);
1659  
1660          expectWithMessage("Navigation usage audio device address")
1661                  .that(mediaDeviceAddress).isEqualTo(NAVIGATION_TEST_DEVICE);
1662      }
1663  
1664      @Test
getOutputDeviceAddressForUsage_forInvalidUsage_fails()1665      public void getOutputDeviceAddressForUsage_forInvalidUsage_fails() throws Exception {
1666          CarAudioService service = setUpAudioService();
1667  
1668          IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
1669                  service.getOutputDeviceAddressForUsage(PRIMARY_AUDIO_ZONE,
1670                          INVALID_USAGE));
1671  
1672          expectWithMessage("Invalid usage audio device address exception")
1673                  .that(thrown).hasMessageThat().contains("Invalid audio attribute " + INVALID_USAGE);
1674      }
1675  
1676      @Test
getOutputDeviceAddressForUsage_forVirtualUsage_fails()1677      public void getOutputDeviceAddressForUsage_forVirtualUsage_fails() throws Exception {
1678          CarAudioService service = setUpAudioService();
1679  
1680          IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
1681                  service.getOutputDeviceAddressForUsage(PRIMARY_AUDIO_ZONE,
1682                          AudioManagerHelper.getUsageVirtualSource()));
1683  
1684          expectWithMessage("Invalid context audio device address exception")
1685                  .that(thrown).hasMessageThat()
1686                  .contains("invalid");
1687      }
1688  
1689      @Test
getOutputDeviceAddressForUsage_onSecondaryZone_forMusicUsage()1690      public void getOutputDeviceAddressForUsage_onSecondaryZone_forMusicUsage() throws Exception {
1691          CarAudioService service = setUpAudioService();
1692  
1693          String mediaDeviceAddress = service.getOutputDeviceAddressForUsage(
1694                  TEST_REAR_LEFT_ZONE_ID, USAGE_MEDIA);
1695  
1696          expectWithMessage("Media usage audio device address for secondary zone")
1697                  .that(mediaDeviceAddress).isEqualTo(SECONDARY_TEST_DEVICE_CONFIG_0);
1698      }
1699  
1700      @Test
getSuggestedAudioContextForZone_inPrimaryZone()1701      public void getSuggestedAudioContextForZone_inPrimaryZone() throws Exception {
1702          CarAudioService service = setUpAudioService();
1703          int defaultAudioContext = service.getCarAudioContext()
1704                  .getContextForAudioAttribute(CAR_DEFAULT_AUDIO_ATTRIBUTE);
1705  
1706          expectWithMessage("Suggested audio context for primary zone")
1707                  .that(service.getSuggestedAudioContextForZone(PRIMARY_AUDIO_ZONE))
1708                  .isEqualTo(defaultAudioContext);
1709      }
1710  
1711      @Test
getSuggestedAudioContextForZone_inSecondaryZone()1712      public void getSuggestedAudioContextForZone_inSecondaryZone() throws Exception {
1713          CarAudioService service = setUpAudioService();
1714          int defaultAudioContext = service.getCarAudioContext()
1715                  .getContextForAudioAttribute(CAR_DEFAULT_AUDIO_ATTRIBUTE);
1716  
1717          expectWithMessage("Suggested audio context for secondary zone")
1718                  .that(service.getSuggestedAudioContextForZone(TEST_REAR_LEFT_ZONE_ID))
1719                  .isEqualTo(defaultAudioContext);
1720      }
1721  
1722      @Test
getSuggestedAudioContextForZone_inInvalidZone()1723      public void getSuggestedAudioContextForZone_inInvalidZone() throws Exception {
1724          CarAudioService service = setUpAudioService();
1725  
1726          expectWithMessage("Suggested audio context for invalid zone")
1727                  .that(service.getSuggestedAudioContextForZone(INVALID_AUDIO_ZONE))
1728                  .isEqualTo(CarAudioContext.getInvalidContext());
1729      }
1730  
1731      @Test
isVolumeGroupMuted_noSetVolumeGroupMute()1732      public void isVolumeGroupMuted_noSetVolumeGroupMute() throws Exception {
1733          CarAudioService service = setUpAudioService();
1734  
1735          expectWithMessage("Volume group mute for default state")
1736                  .that(service.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE,
1737                          TEST_PRIMARY_ZONE_GROUP_0)).isFalse();
1738      }
1739  
1740      @Test
isVolumeGroupMuted_setVolumeGroupMuted_isFalse()1741      public void isVolumeGroupMuted_setVolumeGroupMuted_isFalse() throws Exception {
1742          CarAudioService service = setUpAudioService();
1743          service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
1744                  /* mute= */ true, TEST_FLAGS);
1745  
1746          service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
1747                  /* mute= */ false, TEST_FLAGS);
1748  
1749          expectWithMessage("Volume group muted after mute and unmute")
1750                  .that(service.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE,
1751                          TEST_PRIMARY_ZONE_GROUP_0)).isFalse();
1752      }
1753  
1754      @Test
isVolumeGroupMuted_setVolumeGroupMuted_isTrue()1755      public void isVolumeGroupMuted_setVolumeGroupMuted_isTrue() throws Exception {
1756          CarAudioService service = setUpAudioService();
1757  
1758          service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
1759                  /* mute= */ true, TEST_FLAGS);
1760          expectWithMessage("Volume group muted after mute")
1761                  .that(service.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE,
1762                          TEST_PRIMARY_ZONE_GROUP_0)).isTrue();
1763      }
1764  
1765      @Test
isVolumeGroupMuted_withVolumeGroupMutingDisabled()1766      public void isVolumeGroupMuted_withVolumeGroupMutingDisabled() throws Exception {
1767          when(mMockResources.getBoolean(audioUseCarVolumeGroupMuting)).thenReturn(false);
1768          CarAudioService nonVolumeGroupMutingAudioService =
1769                  setUpAudioServiceWithDisabledResource(audioUseCarVolumeGroupMuting);
1770  
1771          expectWithMessage("Volume group for disabled volume group muting")
1772                  .that(nonVolumeGroupMutingAudioService.isVolumeGroupMuted(
1773                          PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0))
1774                  .isFalse();
1775      }
1776  
1777      @Test
getGroupMaxVolume_forPrimaryZone()1778      public void getGroupMaxVolume_forPrimaryZone() throws Exception {
1779          CarAudioService service = setUpAudioService();
1780  
1781          expectWithMessage("Group max volume for primary audio zone and group")
1782                  .that(service.getGroupMaxVolume(PRIMARY_AUDIO_ZONE,
1783                          TEST_PRIMARY_ZONE_GROUP_0)).isEqualTo((MAX_GAIN - MIN_GAIN) / STEP_SIZE);
1784      }
1785  
1786      @Test
getGroupMinVolume_forPrimaryZone()1787      public void getGroupMinVolume_forPrimaryZone() throws Exception {
1788          CarAudioService service = setUpAudioService();
1789  
1790          expectWithMessage("Group Min Volume for primary audio zone and group")
1791                  .that(service.getGroupMinVolume(PRIMARY_AUDIO_ZONE,
1792                          TEST_PRIMARY_ZONE_GROUP_0)).isEqualTo(0);
1793      }
1794  
1795      @Test
getGroupCurrentVolume_forPrimaryZone()1796      public void getGroupCurrentVolume_forPrimaryZone() throws Exception {
1797          CarAudioService service = setUpAudioService();
1798  
1799          expectWithMessage("Current group volume for primary audio zone and group")
1800                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
1801                          TEST_PRIMARY_ZONE_GROUP_0))
1802                  .isEqualTo((DEFAULT_GAIN - MIN_GAIN) / STEP_SIZE);
1803      }
1804  
1805      @Test
getGroupMaxVolume_withNoDynamicRouting()1806      public void getGroupMaxVolume_withNoDynamicRouting() throws Exception {
1807          CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
1808  
1809          nonDynamicAudioService.getGroupMaxVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0);
1810  
1811          verify(mAudioManager).getStreamMaxVolume(
1812                  CarAudioDynamicRouting.STREAM_TYPES[TEST_PRIMARY_ZONE_GROUP_0]);
1813      }
1814  
1815      @Test
getGroupMinVolume_withNoDynamicRouting()1816      public void getGroupMinVolume_withNoDynamicRouting() throws Exception {
1817          CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
1818  
1819          nonDynamicAudioService.getGroupMinVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0);
1820  
1821          verify(mAudioManager).getStreamMinVolume(
1822                  CarAudioDynamicRouting.STREAM_TYPES[TEST_PRIMARY_ZONE_GROUP_0]);
1823      }
1824  
1825      @Test
getGroupCurrentVolume_withNoDynamicRouting()1826      public void getGroupCurrentVolume_withNoDynamicRouting() throws Exception {
1827          CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
1828  
1829          nonDynamicAudioService.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0);
1830  
1831          verify(mAudioManager).getStreamVolume(
1832                  CarAudioDynamicRouting.STREAM_TYPES[TEST_PRIMARY_ZONE_GROUP_0]);
1833      }
1834  
1835      @Test
setBalanceTowardRight_nonNullValue()1836      public void setBalanceTowardRight_nonNullValue() throws Exception {
1837          CarAudioService service = setUpAudioService();
1838  
1839          service.setBalanceTowardRight(TEST_VALUE);
1840  
1841          verify(mAudioControlWrapperAidl).setBalanceTowardRight(TEST_VALUE);
1842      }
1843  
1844      @Test
setBalanceTowardRight_throws()1845      public void setBalanceTowardRight_throws() throws Exception {
1846          CarAudioService service = setUpAudioService();
1847  
1848          IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, ()
1849                  -> service.setBalanceTowardRight(INVALID_TEST_VALUE));
1850  
1851          expectWithMessage("Out of bounds balance")
1852                  .that(thrown).hasMessageThat()
1853                  .contains(String.format("Balance is out of range of [%f, %f]", -1f, 1f));
1854      }
1855  
1856      @Test
setFadeTowardFront_nonNullValue()1857      public void setFadeTowardFront_nonNullValue() throws Exception {
1858          CarAudioService service = setUpAudioService();
1859  
1860          service.setFadeTowardFront(TEST_VALUE);
1861  
1862          verify(mAudioControlWrapperAidl).setFadeTowardFront(TEST_VALUE);
1863      }
1864  
1865      @Test
setFadeTowardFront_throws()1866      public void setFadeTowardFront_throws() throws Exception {
1867          CarAudioService service = setUpAudioService();
1868  
1869          IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, ()
1870                  -> service.setFadeTowardFront(INVALID_TEST_VALUE));
1871  
1872          expectWithMessage("Out of bounds fade")
1873                  .that(thrown).hasMessageThat()
1874                  .contains(String.format("Fade is out of range of [%f, %f]", -1f, 1f));
1875      }
1876  
1877      @Test
isAudioFeatureEnabled_forDynamicRouting()1878      public void isAudioFeatureEnabled_forDynamicRouting() throws Exception {
1879          CarAudioService service = setUpAudioService();
1880  
1881          expectWithMessage("Dynamic routing audio feature")
1882                  .that(service.isAudioFeatureEnabled(AUDIO_FEATURE_DYNAMIC_ROUTING))
1883                  .isEqualTo(mUseDynamicRouting);
1884      }
1885  
1886      @Test
isAudioFeatureEnabled_forDisabledDynamicRouting()1887      public void isAudioFeatureEnabled_forDisabledDynamicRouting() throws Exception {
1888          CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
1889  
1890          expectWithMessage("Disabled dynamic routing audio feature")
1891                  .that(nonDynamicAudioService.isAudioFeatureEnabled(AUDIO_FEATURE_DYNAMIC_ROUTING))
1892                  .isFalse();
1893      }
1894  
1895      @Test
isAudioFeatureEnabled_forVolumeGroupMuting()1896      public void isAudioFeatureEnabled_forVolumeGroupMuting() throws Exception {
1897          CarAudioService service = setUpAudioService();
1898  
1899          expectWithMessage("Group muting audio feature")
1900                  .that(service.isAudioFeatureEnabled(AUDIO_FEATURE_VOLUME_GROUP_MUTING))
1901                  .isEqualTo(mUseCarVolumeGroupMuting);
1902      }
1903  
1904      @Test
isAudioFeatureEnabled_forDisabledVolumeGroupMuting()1905      public void isAudioFeatureEnabled_forDisabledVolumeGroupMuting() throws Exception {
1906          CarAudioService nonVolumeGroupMutingAudioService =
1907                  setUpAudioServiceWithDisabledResource(audioUseCarVolumeGroupMuting);
1908  
1909          expectWithMessage("Disabled group muting audio feature")
1910                  .that(nonVolumeGroupMutingAudioService
1911                          .isAudioFeatureEnabled(AUDIO_FEATURE_VOLUME_GROUP_MUTING))
1912                  .isFalse();
1913      }
1914  
1915      @Test
isAudioFeatureEnabled_forVolumeGroupEvent()1916      public void isAudioFeatureEnabled_forVolumeGroupEvent() throws Exception {
1917          CarAudioService service = setUpAudioService();
1918  
1919          expectWithMessage("Group events audio feature")
1920                  .that(service.isAudioFeatureEnabled(AUDIO_FEATURE_VOLUME_GROUP_EVENTS))
1921                  .isEqualTo(mUseCarVolumeGroupEvents);
1922      }
1923  
1924      @Test
isAudioFeatureEnabled_forDisabledVolumeGroupEvent()1925      public void isAudioFeatureEnabled_forDisabledVolumeGroupEvent() throws Exception {
1926          CarAudioService nonVolumeGroupEventsAudioService =
1927                  setUpAudioServiceWithDisabledResource(audioUseCarVolumeGroupEvent);
1928  
1929          expectWithMessage("Disabled group event audio feature")
1930                  .that(nonVolumeGroupEventsAudioService
1931                          .isAudioFeatureEnabled(AUDIO_FEATURE_VOLUME_GROUP_EVENTS))
1932                  .isFalse();
1933      }
1934  
1935      @Test
isAudioFeatureEnabled_forUnrecognizableAudioFeature_throws()1936      public void isAudioFeatureEnabled_forUnrecognizableAudioFeature_throws() throws Exception {
1937          CarAudioService service = setUpAudioService();
1938  
1939          IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class,
1940                  () -> service.isAudioFeatureEnabled(INVALID_AUDIO_FEATURE));
1941  
1942          expectWithMessage("Unknown audio feature")
1943                  .that(thrown).hasMessageThat()
1944                  .contains("Unknown Audio Feature type: " + INVALID_AUDIO_FEATURE);
1945      }
1946  
1947      @Test
isAudioFeatureEnabled_forDisabledOemService()1948      public void isAudioFeatureEnabled_forDisabledOemService() throws Exception {
1949          CarAudioService service = setUpAudioService();
1950  
1951          boolean isEnabled =
1952                  service.isAudioFeatureEnabled(AUDIO_FEATURE_OEM_AUDIO_SERVICE);
1953  
1954          expectWithMessage("Oem service enabled with disabled oem service")
1955                  .that(isEnabled).isFalse();
1956      }
1957  
1958      @Test
isAudioFeatureEnabled_withEnabledFocusService()1959      public void isAudioFeatureEnabled_withEnabledFocusService() throws Exception {
1960          CarOemAudioFocusProxyService focusProxyService = mock(CarOemAudioFocusProxyService.class);
1961          when(mMockCarOemProxyService.isOemServiceEnabled()).thenReturn(true);
1962          when(mMockCarOemProxyService.getCarOemAudioFocusService()).thenReturn(focusProxyService);
1963          CarAudioService service = setUpAudioService();
1964  
1965          boolean isEnabled =
1966                  service.isAudioFeatureEnabled(AUDIO_FEATURE_OEM_AUDIO_SERVICE);
1967  
1968          expectWithMessage("Oem service enabled with enabled focus service")
1969                  .that(isEnabled).isTrue();
1970      }
1971  
1972      @Test
isAudioFeatureEnabled_withEnabledVolumeService()1973      public void isAudioFeatureEnabled_withEnabledVolumeService() throws Exception {
1974          CarOemAudioVolumeProxyService volumeProxyService =
1975                  mock(CarOemAudioVolumeProxyService.class);
1976          when(mMockCarOemProxyService.isOemServiceEnabled()).thenReturn(true);
1977          when(mMockCarOemProxyService.getCarOemAudioVolumeService()).thenReturn(volumeProxyService);
1978          CarAudioService service = setUpAudioService();
1979  
1980          boolean isEnabled =
1981                  service.isAudioFeatureEnabled(AUDIO_FEATURE_OEM_AUDIO_SERVICE);
1982  
1983          expectWithMessage("Oem service enabled with enabled volume service")
1984                  .that(isEnabled).isTrue();
1985      }
1986  
1987      @Test
isAudioFeatureEnabled_withEnabledDuckingService()1988      public void isAudioFeatureEnabled_withEnabledDuckingService() throws Exception {
1989          CarOemAudioDuckingProxyService duckingProxyService =
1990                  mock(CarOemAudioDuckingProxyService.class);
1991          when(mMockCarOemProxyService.isOemServiceEnabled()).thenReturn(true);
1992          when(mMockCarOemProxyService.getCarOemAudioDuckingService())
1993                  .thenReturn(duckingProxyService);
1994          CarAudioService service = setUpAudioService();
1995  
1996          boolean isEnabled = service.isAudioFeatureEnabled(AUDIO_FEATURE_OEM_AUDIO_SERVICE);
1997  
1998          expectWithMessage("Oem service enabled with enabled ducking service")
1999                  .that(isEnabled).isTrue();
2000      }
2001  
2002      @Test
isAudioFeatureEnabled_withEnabledAudioMirror()2003      public void isAudioFeatureEnabled_withEnabledAudioMirror() throws Exception {
2004          CarAudioService service = setUpAudioService();
2005  
2006          boolean isEnabled = service.isAudioFeatureEnabled(AUDIO_FEATURE_AUDIO_MIRRORING);
2007  
2008          expectWithMessage("Audio mirror enabled status")
2009                  .that(isEnabled).isTrue();
2010      }
2011  
2012      @Test
isAudioFeatureEnabled_withDisabledAudioMirror()2013      public void isAudioFeatureEnabled_withDisabledAudioMirror() throws Exception {
2014          CarAudioService service = setUpCarAudioServiceWithoutMirroring();
2015  
2016          boolean isEnabled = service.isAudioFeatureEnabled(AUDIO_FEATURE_AUDIO_MIRRORING);
2017  
2018          expectWithMessage("Audio mirror enabled status")
2019                  .that(isEnabled).isFalse();
2020      }
2021  
2022      @Test
isAudioFeatureEnabled_forMinMaxActivationVolume()2023      public void isAudioFeatureEnabled_forMinMaxActivationVolume() throws Exception {
2024          mSetFlagsRule.enableFlags(Flags.FLAG_CAR_AUDIO_MIN_MAX_ACTIVATION_VOLUME);
2025          CarAudioService service = setUpAudioService();
2026  
2027          expectWithMessage("Min/max activation volume feature")
2028                  .that(service.isAudioFeatureEnabled(AUDIO_FEATURE_MIN_MAX_ACTIVATION_VOLUME))
2029                  .isEqualTo(mUseMinMaxActivationVolume);
2030      }
2031  
2032      @Test
isAudioFeatureEnabled_forDisabledMinMaxActivationVolume()2033      public void isAudioFeatureEnabled_forDisabledMinMaxActivationVolume() throws Exception {
2034          mSetFlagsRule.enableFlags(Flags.FLAG_CAR_AUDIO_MIN_MAX_ACTIVATION_VOLUME);
2035          CarAudioService nonMinMaxActivationVolumeAudioService =
2036                  setUpAudioServiceWithDisabledResource(audioUseMinMaxActivationVolume);
2037  
2038          expectWithMessage("Disabled min/max activation volume feature")
2039                  .that(nonMinMaxActivationVolumeAudioService
2040                          .isAudioFeatureEnabled(AUDIO_FEATURE_MIN_MAX_ACTIVATION_VOLUME))
2041                  .isFalse();
2042      }
2043  
2044      @Test
isAudioFeatureEnabled_forMinMaxActivationVolumeWithDisabledFlag()2045      public void isAudioFeatureEnabled_forMinMaxActivationVolumeWithDisabledFlag() throws Exception {
2046          mSetFlagsRule.disableFlags(Flags.FLAG_CAR_AUDIO_MIN_MAX_ACTIVATION_VOLUME);
2047          CarAudioService service = setUpAudioService();
2048  
2049          expectWithMessage("Min/max activation volume feature with disabled feature flag")
2050                  .that(service.isAudioFeatureEnabled(AUDIO_FEATURE_MIN_MAX_ACTIVATION_VOLUME))
2051                  .isFalse();
2052      }
2053  
2054      @Test
onOccupantZoneConfigChanged_noUserAssignedToPrimaryZone()2055      public void onOccupantZoneConfigChanged_noUserAssignedToPrimaryZone() throws Exception {
2056          CarAudioService service = setUpAudioService();
2057          when(mMockOccupantZoneService.getDriverUserId()).thenReturn(UserManagerHelper.USER_NULL);
2058          when(mMockOccupantZoneService.getUserForOccupant(anyInt()))
2059                  .thenReturn(UserManagerHelper.USER_NULL);
2060          ICarOccupantZoneCallback callback = getOccupantZoneCallback();
2061          int prevUserId = service.getUserIdForZone(PRIMARY_AUDIO_ZONE);
2062  
2063          callback.onOccupantZoneConfigChanged(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
2064  
2065          expectWithMessage("User ID before config changed")
2066                  .that(service.getUserIdForZone(PRIMARY_AUDIO_ZONE))
2067                  .isEqualTo(prevUserId);
2068      }
2069  
2070      @Test
onOccupantZoneConfigChanged_userAssignedToPrimaryZone()2071      public void onOccupantZoneConfigChanged_userAssignedToPrimaryZone() throws Exception {
2072          CarAudioService service = setUpAudioService();
2073          when(mMockOccupantZoneService.getDriverUserId()).thenReturn(TEST_DRIVER_USER_ID);
2074          when(mMockOccupantZoneService.getUserForOccupant(anyInt()))
2075                  .thenReturn(TEST_REAR_LEFT_USER_ID);
2076          ICarOccupantZoneCallback callback = getOccupantZoneCallback();
2077  
2078          callback.onOccupantZoneConfigChanged(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
2079  
2080          expectWithMessage("User ID after config changed")
2081                  .that(service.getUserIdForZone(PRIMARY_AUDIO_ZONE))
2082                  .isEqualTo(TEST_REAR_LEFT_USER_ID);
2083      }
2084  
2085      @Test
onOccupantZoneConfigChanged_afterResettingUser_returnNoUser()2086      public void onOccupantZoneConfigChanged_afterResettingUser_returnNoUser() throws Exception {
2087          CarAudioService service = setUpAudioService();
2088          when(mMockOccupantZoneService.getDriverUserId()).thenReturn(TEST_DRIVER_USER_ID);
2089          when(mMockOccupantZoneService.getUserForOccupant(anyInt()))
2090                  .thenReturn(TEST_REAR_LEFT_USER_ID);
2091          ICarOccupantZoneCallback callback = getOccupantZoneCallback();
2092          callback.onOccupantZoneConfigChanged(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
2093          when(mMockOccupantZoneService.getUserForOccupant(anyInt()))
2094                  .thenReturn(UserManagerHelper.USER_NULL);
2095  
2096          callback.onOccupantZoneConfigChanged(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
2097  
2098          expectWithMessage("User ID config changed to null")
2099                  .that(service.getUserIdForZone(PRIMARY_AUDIO_ZONE))
2100                  .isEqualTo(UserManagerHelper.USER_NULL);
2101      }
2102  
2103      @Test
onOccupantZoneConfigChanged_noOccupantZoneMapping()2104      public void onOccupantZoneConfigChanged_noOccupantZoneMapping() throws Exception {
2105          setUpCarAudioServiceWithoutZoneMapping();
2106          ICarOccupantZoneCallback callback = getOccupantZoneCallback();
2107  
2108          callback.onOccupantZoneConfigChanged(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
2109  
2110          verify(mMockOccupantZoneService, never()).getUserForOccupant(anyInt());
2111      }
2112  
2113      @Test
onOccupantZoneConfigChanged_noOccupantZoneMapping_alreadyAssigned()2114      public void onOccupantZoneConfigChanged_noOccupantZoneMapping_alreadyAssigned()
2115              throws Exception {
2116          when(mMockOccupantZoneService.getDriverUserId()).thenReturn(TEST_DRIVER_USER_ID);
2117          CarAudioService noZoneMappingAudioService = setUpCarAudioServiceWithoutZoneMapping();
2118          ICarOccupantZoneCallback callback = getOccupantZoneCallback();
2119          callback.onOccupantZoneConfigChanged(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
2120          callback.onOccupantZoneConfigChanged(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
2121  
2122          verify(mMockOccupantZoneService, never()).getUserForOccupant(anyInt());
2123          expectWithMessage("Occupant Zone for primary zone")
2124                  .that(noZoneMappingAudioService.getUserIdForZone(PRIMARY_AUDIO_ZONE))
2125                  .isEqualTo(TEST_DRIVER_USER_ID);
2126      }
2127  
2128      @Test
onOccupantZoneConfigChanged_multipleZones()2129      public void onOccupantZoneConfigChanged_multipleZones() throws Exception {
2130          CarAudioService service = setUpAudioService();
2131          when(mMockOccupantZoneService.getDriverUserId()).thenReturn(TEST_DRIVER_USER_ID);
2132          when(mMockOccupantZoneService.getUserForOccupant(anyInt()))
2133                  .thenReturn(TEST_REAR_LEFT_USER_ID, TEST_REAR_RIGHT_USER_ID);
2134          ICarOccupantZoneCallback callback = getOccupantZoneCallback();
2135  
2136          callback.onOccupantZoneConfigChanged(CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
2137  
2138          expectWithMessage("User ID for primary and secondary zone after config changed")
2139                  .that(service.getUserIdForZone(PRIMARY_AUDIO_ZONE))
2140                  .isNotEqualTo(service.getUserIdForZone(TEST_REAR_LEFT_ZONE_ID));
2141          expectWithMessage("Secondary user ID config changed")
2142                  .that(service.getUserIdForZone(TEST_REAR_LEFT_ZONE_ID))
2143                  .isEqualTo(TEST_REAR_RIGHT_USER_ID);
2144      }
2145  
2146      @Test
init_forUserAlreadySetup_callsInternalConfigChange()2147      public void init_forUserAlreadySetup_callsInternalConfigChange() throws Exception {
2148          when(mMockOccupantZoneService.getDriverUserId()).thenReturn(TEST_DRIVER_USER_ID);
2149          when(mMockOccupantZoneService.getUserForOccupant(TEST_DRIVER_OCCUPANT_ZONE_ID))
2150                  .thenReturn(TEST_DRIVER_USER_ID);
2151          when(mMockOccupantZoneService.getUserForOccupant(TEST_REAR_RIGHT_OCCUPANT_ZONE_ID))
2152                  .thenReturn(TEST_REAR_RIGHT_USER_ID);
2153          CarAudioService service = setUpAudioServiceWithoutInit();
2154  
2155          service.init();
2156  
2157          waitForInternalCallback();
2158          expectWithMessage("User ID for primary zone for user available at init")
2159                  .that(service.getUserIdForZone(PRIMARY_AUDIO_ZONE))
2160                  .isEqualTo(TEST_DRIVER_USER_ID);
2161          expectWithMessage("User ID secondary zone for user available at init")
2162                  .that(service.getUserIdForZone(TEST_REAR_RIGHT_ZONE_ID))
2163                  .isEqualTo(TEST_REAR_RIGHT_USER_ID);
2164      }
2165  
2166      @Test
init_withAudioModuleCallbackFeatureDisabled()2167      public void init_withAudioModuleCallbackFeatureDisabled() throws Exception {
2168          when(mAudioControlWrapperAidl.supportsFeature(
2169                  AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_MODULE_CALLBACK)).thenReturn(false);
2170  
2171          setUpAudioService();
2172  
2173          verify(mAudioControlWrapperAidl, never()).setModuleChangeCallback(any());
2174      }
2175  
2176      @Test
init_withAudioFocusFeatureDisabled()2177      public void init_withAudioFocusFeatureDisabled() throws Exception {
2178          when(mAudioControlWrapperAidl.supportsFeature(
2179                  AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_FOCUS)).thenReturn(false);
2180  
2181          setUpAudioService();
2182  
2183          verify(mAudioControlWrapperAidl, never()).registerFocusListener(any());
2184      }
2185  
2186      @Test
init_withAudioGainCallbackFeatureDisabled()2187      public void init_withAudioGainCallbackFeatureDisabled() throws Exception {
2188          when(mAudioControlWrapperAidl.supportsFeature(
2189                  AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_GAIN_CALLBACK)).thenReturn(false);
2190  
2191          setUpAudioService();
2192  
2193          verify(mAudioControlWrapperAidl, never()).registerAudioGainCallback(any());
2194      }
2195  
2196      @Test
serviceDied_registersAudioGainCallback()2197      public void serviceDied_registersAudioGainCallback() throws Exception {
2198          setUpAudioService();
2199          ArgumentCaptor<AudioControlDeathRecipient> captor =
2200                  ArgumentCaptor.forClass(AudioControlDeathRecipient.class);
2201          verify(mAudioControlWrapperAidl).linkToDeath(captor.capture());
2202          AudioControlDeathRecipient runnable = captor.getValue();
2203          reset(mAudioControlWrapperAidl);
2204  
2205          runnable.serviceDied();
2206  
2207          verify(mAudioControlWrapperAidl).registerAudioGainCallback(any());
2208      }
2209  
2210      @Test
serviceDied_withNullAudioGainCallback()2211      public void serviceDied_withNullAudioGainCallback() throws Exception {
2212          when(mAudioControlWrapperAidl.supportsFeature(
2213                  AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_GAIN_CALLBACK)).thenReturn(false);
2214          setUpAudioService();
2215          ArgumentCaptor<AudioControlDeathRecipient> captor =
2216                  ArgumentCaptor.forClass(AudioControlDeathRecipient.class);
2217          verify(mAudioControlWrapperAidl).linkToDeath(captor.capture());
2218          AudioControlDeathRecipient runnable = captor.getValue();
2219          reset(mAudioControlWrapperAidl);
2220  
2221          runnable.serviceDied();
2222  
2223          verify(mAudioControlWrapperAidl, never()).registerAudioGainCallback(any());
2224      }
2225  
2226      @Test
serviceDied_registersFocusListener()2227      public void serviceDied_registersFocusListener() throws Exception {
2228          setUpAudioService();
2229          ArgumentCaptor<AudioControlDeathRecipient> captor =
2230                  ArgumentCaptor.forClass(AudioControlDeathRecipient.class);
2231          verify(mAudioControlWrapperAidl).linkToDeath(captor.capture());
2232          AudioControlDeathRecipient runnable = captor.getValue();
2233          reset(mAudioControlWrapperAidl);
2234  
2235          runnable.serviceDied();
2236  
2237          verify(mAudioControlWrapperAidl).registerFocusListener(any());
2238      }
2239  
2240      @Test
serviceDied_withAudioServerNotRunning()2241      public void serviceDied_withAudioServerNotRunning() throws Exception {
2242          setUpAudioService();
2243          ArgumentCaptor<AudioControlDeathRecipient> captor =
2244                  ArgumentCaptor.forClass(AudioControlDeathRecipient.class);
2245          verify(mAudioControlWrapperAidl).linkToDeath(captor.capture());
2246          AudioControlDeathRecipient runnable = captor.getValue();
2247          reset(mAudioControlWrapperAidl);
2248          when(mAudioManager.isAudioServerRunning()).thenReturn(false);
2249  
2250          runnable.serviceDied();
2251  
2252          verify(mAudioControlWrapperAidl, never()).registerAudioGainCallback(any());
2253          verify(mAudioControlWrapperAidl, never()).registerFocusListener(any());
2254      }
2255  
2256      @Test
serviceDied_withAudioServerDown()2257      public void serviceDied_withAudioServerDown() throws Exception {
2258          CarAudioService service = setUpAudioService();
2259          ArgumentCaptor<AudioControlDeathRecipient> captor =
2260                  ArgumentCaptor.forClass(AudioControlDeathRecipient.class);
2261          verify(mAudioControlWrapperAidl).linkToDeath(captor.capture());
2262          AudioControlDeathRecipient runnable = captor.getValue();
2263          reset(mAudioControlWrapperAidl);
2264          service.releaseAudioCallbacks(/* isAudioServerDown= */ true);
2265  
2266          runnable.serviceDied();
2267  
2268          verify(mAudioControlWrapperAidl, never()).registerAudioGainCallback(any());
2269          verify(mAudioControlWrapperAidl, never()).registerFocusListener(any());
2270          verify(mAudioControlWrapperAidl, never()).setModuleChangeCallback(any());
2271      }
2272  
2273      @Test
serviceDied_setsModuleChangeCallback()2274      public void serviceDied_setsModuleChangeCallback() throws Exception {
2275          setUpAudioService();
2276          ArgumentCaptor<AudioControlDeathRecipient> captor =
2277                  ArgumentCaptor.forClass(AudioControlDeathRecipient.class);
2278          verify(mAudioControlWrapperAidl).linkToDeath(captor.capture());
2279          AudioControlDeathRecipient runnable = captor.getValue();
2280          reset(mAudioControlWrapperAidl);
2281  
2282          runnable.serviceDied();
2283  
2284          verify(mAudioControlWrapperAidl).setModuleChangeCallback(any());
2285      }
2286  
2287      @Test
serviceDied_withNullModuleChangeCallback()2288      public void serviceDied_withNullModuleChangeCallback() throws Exception {
2289          when(mAudioControlWrapperAidl.supportsFeature(
2290                  AudioControlWrapper.AUDIOCONTROL_FEATURE_AUDIO_MODULE_CALLBACK)).thenReturn(false);
2291          setUpAudioService();
2292          ArgumentCaptor<AudioControlDeathRecipient> captor =
2293                  ArgumentCaptor.forClass(AudioControlDeathRecipient.class);
2294          verify(mAudioControlWrapperAidl).linkToDeath(captor.capture());
2295          AudioControlDeathRecipient runnable = captor.getValue();
2296          reset(mAudioControlWrapperAidl);
2297  
2298          runnable.serviceDied();
2299  
2300          verify(mAudioControlWrapperAidl, never()).setModuleChangeCallback(any());
2301      }
2302  
2303      @Test
getVolumeGroupIdForAudioContext_forPrimaryGroup()2304      public void getVolumeGroupIdForAudioContext_forPrimaryGroup() throws Exception {
2305          CarAudioService service = setUpAudioService();
2306  
2307          expectWithMessage("Volume group ID for primary audio zone")
2308                  .that(service.getVolumeGroupIdForAudioContext(PRIMARY_AUDIO_ZONE,
2309                          CarAudioContext.MUSIC))
2310                  .isEqualTo(TEST_PRIMARY_ZONE_GROUP_0);
2311      }
2312  
2313      @Test
getVolumeGroupIdForAudioAttribute()2314      public void getVolumeGroupIdForAudioAttribute() throws Exception {
2315          CarAudioService service = setUpAudioService();
2316  
2317          expectWithMessage("Volume group ID for primary audio zone")
2318                  .that(service.getVolumeGroupIdForAudioAttribute(PRIMARY_AUDIO_ZONE,
2319                          CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA)))
2320                  .isEqualTo(TEST_PRIMARY_ZONE_GROUP_0);
2321      }
2322  
2323      @Test
getVolumeGroupIdForAudioAttribute_withNullAttribute_fails()2324      public void getVolumeGroupIdForAudioAttribute_withNullAttribute_fails() throws Exception {
2325          CarAudioService service = setUpAudioService();
2326  
2327          NullPointerException thrown = assertThrows(NullPointerException.class, () ->
2328                  service.getVolumeGroupIdForAudioAttribute(PRIMARY_AUDIO_ZONE,
2329                  /* attributes= */ null));
2330  
2331          expectWithMessage("Null audio attribute exception").that(thrown).hasMessageThat()
2332                  .contains("Audio attributes");
2333      }
2334  
2335      @Test
getVolumeGroupIdForAudioAttribute_withInvalidZoneId_fails()2336      public void getVolumeGroupIdForAudioAttribute_withInvalidZoneId_fails() throws Exception {
2337          CarAudioService service = setUpAudioService();
2338  
2339          IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () ->
2340                  service.getVolumeGroupIdForAudioAttribute(INVALID_AUDIO_ZONE,
2341                          CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA)));
2342  
2343          expectWithMessage("Invalid audio zone exception").that(thrown).hasMessageThat()
2344                  .contains("Invalid audio zone Id");
2345      }
2346  
2347      @Test
getInputDevicesForZoneId_primaryZone()2348      public void getInputDevicesForZoneId_primaryZone() throws Exception {
2349          CarAudioService service = setUpAudioService();
2350  
2351          expectWithMessage("Get input device for primary zone id")
2352                  .that(service.getInputDevicesForZoneId(PRIMARY_AUDIO_ZONE))
2353                  .containsExactly(new AudioDeviceAttributes(mMicrophoneInputDevice));
2354      }
2355  
2356      @Test
getExternalSources_forSingleDevice()2357      public void getExternalSources_forSingleDevice() throws Exception {
2358          CarAudioService service = setUpAudioService();
2359          AudioDeviceInfo[] inputDevices = generateInputDeviceInfos();
2360  
2361          expectWithMessage("External input device addresses")
2362                  .that(service.getExternalSources())
2363                  .asList().containsExactly(inputDevices[1].getAddress());
2364      }
2365  
2366      @Test
setAudioEnabled_forEnabledVolumeGroupMuting()2367      public void setAudioEnabled_forEnabledVolumeGroupMuting() throws Exception {
2368          CarAudioService service = setUpAudioService();
2369  
2370          service.setAudioEnabled(/* isAudioEnabled= */ true);
2371  
2372          verify(mAudioControlWrapperAidl).onDevicesToMuteChange(any());
2373      }
2374  
2375      @Test
setAudioEnabled_forDisabledVolumeGroupMuting()2376      public void setAudioEnabled_forDisabledVolumeGroupMuting() throws Exception {
2377          CarAudioService nonVolumeGroupMutingAudioService =
2378                  setUpAudioServiceWithDisabledResource(audioUseCarVolumeGroupMuting);
2379  
2380          nonVolumeGroupMutingAudioService.setAudioEnabled(/* isAudioEnabled= */ true);
2381  
2382          verify(mAudioControlWrapperAidl, never()).onDevicesToMuteChange(any());
2383      }
2384  
2385      @Test
onAudioServerDown_forCarAudioServiceCallback()2386      public void onAudioServerDown_forCarAudioServiceCallback() throws Exception {
2387          setUpAudioService();
2388          AudioServerStateCallback callback = getAudioServerStateCallback();
2389          AudioDeviceCallback deviceCallback = captureAudioDeviceCallback();
2390          AudioPlaybackCallback playbackCallback = getCarAudioPlaybackCallback();
2391          ICarOccupantZoneCallback occupantZoneCallback = getOccupantZoneCallback();
2392          KeyEventListener keyInputListener = getAudioKeyEventListener();
2393  
2394          callback.onAudioServerDown();
2395  
2396          verify(mAudioControlWrapperAidl, never()).onDevicesToMuteChange(any());
2397          // Routing policy is not unregistered on audio server going down
2398          verify(mAudioManager, times(AUDIO_SERVICE_POLICY_REGISTRATIONS - 1))
2399                  .unregisterAudioPolicy(any());
2400          verify(mAudioManager).unregisterAudioPlaybackCallback(playbackCallback);
2401          verify(mAudioControlWrapperAidl).unregisterFocusListener();
2402          verify(mAudioManager, never()).unregisterVolumeGroupCallback(any());
2403          verify(mMockPowerService).removePowerPolicyListener(any());
2404          verify(mMockTelephonyManager).unregisterTelephonyCallback(any());
2405          verify(mAudioManager).unregisterAudioDeviceCallback(deviceCallback);
2406          verify(mAudioControlWrapperAidl).clearModuleChangeCallback();
2407          verify(mMockOccupantZoneService).unregisterCallback(occupantZoneCallback);
2408          verify(mMockCarInputService).unregisterKeyEventListener(keyInputListener);
2409          verify(mAudioControlWrapperAidl, never()).unlinkToDeath();
2410      }
2411  
2412      @Test
onAudioServerDown_forCarAudioServiceCallback_withFadeManagerEnabled()2413      public void onAudioServerDown_forCarAudioServiceCallback_withFadeManagerEnabled()
2414              throws Exception {
2415          setUpCarAudioServiceWithFadeManagerEnabled();
2416          AudioServerStateCallback callback = getAudioServerStateCallback();
2417          AudioDeviceCallback deviceCallback = captureAudioDeviceCallback();
2418          AudioPlaybackCallback playbackCallback = getCarAudioPlaybackCallback();
2419          ICarOccupantZoneCallback occupantZoneCallback = getOccupantZoneCallback();
2420          KeyEventListener keyInputListener = getAudioKeyEventListener();
2421  
2422          callback.onAudioServerDown();
2423  
2424          verify(mAudioControlWrapperAidl, never()).onDevicesToMuteChange(any());
2425          // Routing policy is not unregistered on audio server going down
2426          verify(mAudioManager, times(AUDIO_SERVICE_POLICY_REGISTRATIONS_WITH_FADE_MANAGER - 1))
2427                  .unregisterAudioPolicy(any());
2428          verify(mAudioManager).unregisterAudioPlaybackCallback(playbackCallback);
2429          verify(mAudioControlWrapperAidl).unregisterFocusListener();
2430          verify(mAudioManager, never()).unregisterVolumeGroupCallback(any());
2431          verify(mMockPowerService).removePowerPolicyListener(any());
2432          verify(mMockTelephonyManager).unregisterTelephonyCallback(any());
2433          verify(mAudioManager).unregisterAudioDeviceCallback(deviceCallback);
2434          verify(mAudioControlWrapperAidl).clearModuleChangeCallback();
2435          verify(mMockOccupantZoneService).unregisterCallback(occupantZoneCallback);
2436          verify(mMockCarInputService).unregisterKeyEventListener(keyInputListener);
2437          verify(mAudioControlWrapperAidl, never()).unlinkToDeath();
2438      }
2439  
2440      @Test
onAudioServerDown_forCarAudioServiceCallback_withCoreVolumeAndRouting()2441      public void onAudioServerDown_forCarAudioServiceCallback_withCoreVolumeAndRouting()
2442              throws Exception {
2443          setUpCarAudioServiceUsingCoreAudioRoutingAndVolume();
2444          AudioServerStateCallback callback = getAudioServerStateCallback();
2445          AudioDeviceCallback deviceCallback = captureAudioDeviceCallback();
2446          AudioPlaybackCallback playbackCallback = getCarAudioPlaybackCallback();
2447          ICarOccupantZoneCallback occupantZoneCallback = getOccupantZoneCallback();
2448          KeyEventListener keyInputListener = getAudioKeyEventListener();
2449  
2450          callback.onAudioServerDown();
2451  
2452          verify(mAudioControlWrapperAidl, never()).onDevicesToMuteChange(any());
2453          // Routing policy is not unregistered on audio server going down
2454          verify(mAudioManager, times(AUDIO_SERVICE_POLICY_REGISTRATIONS - 1))
2455                  .unregisterAudioPolicy(any());
2456          verify(mAudioManager).unregisterAudioPlaybackCallback(playbackCallback);
2457          verify(mAudioControlWrapperAidl).unregisterFocusListener();
2458          verify(mAudioManager).unregisterVolumeGroupCallback(any());
2459          verify(mMockPowerService).removePowerPolicyListener(any());
2460          verify(mMockTelephonyManager).unregisterTelephonyCallback(any());
2461          verify(mAudioManager).unregisterAudioDeviceCallback(deviceCallback);
2462          verify(mAudioControlWrapperAidl).clearModuleChangeCallback();
2463          verify(mMockOccupantZoneService).unregisterCallback(occupantZoneCallback);
2464          verify(mMockCarInputService).unregisterKeyEventListener(keyInputListener);
2465          verify(mAudioControlWrapperAidl, never()).unlinkToDeath();
2466      }
2467  
2468      @Test
onAudioServerUp_forCarAudioServiceCallback()2469      public void onAudioServerUp_forCarAudioServiceCallback() throws Exception {
2470          CarAudioService service = setUpAudioService();
2471          AudioServerStateCallback callback = getAudioServerStateCallback();
2472          callback.onAudioServerDown();
2473  
2474          callback.onAudioServerUp();
2475  
2476          waitForInternalCallback();
2477          expectWithMessage("Re-initialized Car Audio Service Zones")
2478                  .that(service.getAudioZoneIds()).asList()
2479                  .containsExactly(PRIMARY_AUDIO_ZONE, TEST_REAR_LEFT_ZONE_ID,
2480                          TEST_REAR_RIGHT_ZONE_ID, TEST_FRONT_ZONE_ID, TEST_REAR_ROW_3_ZONE_ID);
2481          // Each callback should register twice the registration from init for each required callback
2482          verify(mAudioManager, times(2 * AUDIO_SERVICE_POLICY_REGISTRATIONS))
2483                  .registerAudioPolicy(any());
2484          verify(mAudioManager, times(2 * AUDIO_SERVICE_CALLBACKS_REGISTRATION))
2485                  .registerAudioPlaybackCallback(any(), any());
2486          verify(mAudioControlWrapperAidl, times(2 * AUDIO_SERVICE_CALLBACKS_REGISTRATION))
2487                  .registerFocusListener(any());
2488          verify(mAudioManager, never()).registerVolumeGroupCallback(any(), any());
2489          verify(mMockPowerService, times(2 * AUDIO_SERVICE_CALLBACKS_REGISTRATION))
2490                  .addPowerPolicyListener(any(), any());
2491          verify(mAudioManager, times(2 * AUDIO_SERVICE_CALLBACKS_REGISTRATION))
2492                  .registerAudioDeviceCallback(any(), any());
2493          verify(mAudioControlWrapperAidl, times(2 * AUDIO_SERVICE_CALLBACKS_REGISTRATION))
2494                  .setModuleChangeCallback(any());
2495          verify(mMockOccupantZoneService, times(2 * AUDIO_SERVICE_CALLBACKS_REGISTRATION))
2496                  .registerCallback(any());
2497          verify(mMockCarInputService, times(2 * AUDIO_SERVICE_CALLBACKS_REGISTRATION))
2498                  .registerKeyEventListener(any(), any());
2499          verify(mAudioControlWrapperAidl, times(2 * AUDIO_SERVICE_CALLBACKS_REGISTRATION))
2500                  .linkToDeath(any());
2501      }
2502  
2503      @Test
onAudioServerUp_forCarAudioServiceCallback_withFadeManagerEnabled()2504      public void onAudioServerUp_forCarAudioServiceCallback_withFadeManagerEnabled()
2505              throws Exception {
2506          CarAudioService service = setUpCarAudioServiceWithFadeManagerEnabled();
2507          AudioServerStateCallback callback = getAudioServerStateCallback();
2508          callback.onAudioServerDown();
2509  
2510          callback.onAudioServerUp();
2511  
2512          expectWithMessage("Re-initialized Car Audio Service Zones")
2513                  .that(service.getAudioZoneIds()).asList()
2514                  .containsExactly(PRIMARY_AUDIO_ZONE, TEST_REAR_LEFT_ZONE_ID,
2515                          TEST_REAR_RIGHT_ZONE_ID, TEST_FRONT_ZONE_ID, TEST_REAR_ROW_3_ZONE_ID);
2516          // Each callback should register twice the registration from init for each required callback
2517          verify(mAudioManager, times(2 * AUDIO_SERVICE_POLICY_REGISTRATIONS_WITH_FADE_MANAGER))
2518                  .registerAudioPolicy(any());
2519          verify(mAudioManager, times(2 * AUDIO_SERVICE_CALLBACKS_REGISTRATION))
2520                  .registerAudioPlaybackCallback(any(), any());
2521          verify(mAudioControlWrapperAidl, times(2 * AUDIO_SERVICE_CALLBACKS_REGISTRATION))
2522                  .registerFocusListener(any());
2523          verify(mAudioManager, never()).registerVolumeGroupCallback(any(), any());
2524          verify(mMockPowerService, times(2 * AUDIO_SERVICE_CALLBACKS_REGISTRATION))
2525                  .addPowerPolicyListener(any(), any());
2526          verify(mAudioManager, times(2 * AUDIO_SERVICE_CALLBACKS_REGISTRATION))
2527                  .registerAudioDeviceCallback(any(), any());
2528          verify(mAudioControlWrapperAidl, times(2 * AUDIO_SERVICE_CALLBACKS_REGISTRATION))
2529                  .setModuleChangeCallback(any());
2530          verify(mMockOccupantZoneService, times(2 * AUDIO_SERVICE_CALLBACKS_REGISTRATION))
2531                  .registerCallback(any());
2532          verify(mMockCarInputService, times(2 * AUDIO_SERVICE_CALLBACKS_REGISTRATION))
2533                  .registerKeyEventListener(any(), any());
2534          verify(mAudioControlWrapperAidl, times(2 * AUDIO_SERVICE_CALLBACKS_REGISTRATION))
2535                  .linkToDeath(any());
2536      }
2537  
2538  
2539      @Test
onAudioServerUp_forCarAudioServiceCallback_withCoreVolumeAndRouting()2540      public void onAudioServerUp_forCarAudioServiceCallback_withCoreVolumeAndRouting()
2541              throws Exception {
2542          CarAudioService service = setUpCarAudioServiceUsingCoreAudioRoutingAndVolume();
2543          AudioServerStateCallback callback = getAudioServerStateCallback();
2544          callback.onAudioServerDown();
2545  
2546          callback.onAudioServerUp();
2547  
2548          expectWithMessage("Re-initialized Car Audio Service Zones")
2549                  .that(service.getAudioZoneIds()).asList()
2550                  .containsExactly(PRIMARY_AUDIO_ZONE);
2551          // Each callback should register twice the registration from init for each required callback
2552          verify(mAudioManager, times(2 * AUDIO_SERVICE_POLICY_REGISTRATIONS))
2553                  .registerAudioPolicy(any());
2554          verify(mAudioManager, times(2 * AUDIO_SERVICE_CALLBACKS_REGISTRATION))
2555                  .registerAudioPlaybackCallback(any(), any());
2556          verify(mAudioControlWrapperAidl, times(2 * AUDIO_SERVICE_CALLBACKS_REGISTRATION))
2557                  .registerFocusListener(any());
2558          verify(mAudioManager, times(2 * AUDIO_SERVICE_CALLBACKS_REGISTRATION))
2559                  .registerVolumeGroupCallback(any(), any());
2560          verify(mMockPowerService, times(2 * AUDIO_SERVICE_CALLBACKS_REGISTRATION))
2561                  .addPowerPolicyListener(any(), any());
2562          verify(mAudioManager, times(2 * AUDIO_SERVICE_CALLBACKS_REGISTRATION))
2563                  .registerAudioDeviceCallback(any(), any());
2564          verify(mAudioControlWrapperAidl, times(2 * AUDIO_SERVICE_CALLBACKS_REGISTRATION))
2565                  .setModuleChangeCallback(any());
2566          verify(mMockOccupantZoneService, times(2 * AUDIO_SERVICE_CALLBACKS_REGISTRATION))
2567                  .registerCallback(any());
2568          verify(mMockCarInputService, times(2 * AUDIO_SERVICE_CALLBACKS_REGISTRATION))
2569                  .registerKeyEventListener(any(), any());
2570          verify(mAudioControlWrapperAidl, times(2 * AUDIO_SERVICE_CALLBACKS_REGISTRATION))
2571                  .linkToDeath(any());
2572      }
2573  
2574      @Test
onAudioServerUp_forUserIdAssignments()2575      public void onAudioServerUp_forUserIdAssignments() throws Exception {
2576          CarAudioService service = setUpAudioService();
2577          when(mMockOccupantZoneService.getDriverUserId()).thenReturn(TEST_DRIVER_USER_ID);
2578          when(mMockOccupantZoneService.getUserForOccupant(TEST_DRIVER_OCCUPANT_ZONE_ID))
2579                  .thenReturn(TEST_DRIVER_USER_ID);
2580          AudioServerStateCallback callback = getAudioServerStateCallback();
2581          callback.onAudioServerDown();
2582  
2583          callback.onAudioServerUp();
2584  
2585          waitForInternalCallback();
2586          expectWithMessage("Re-initialized Car Audio Service Zones")
2587                  .that(service.getAudioZoneIds()).asList()
2588                  .containsExactly(PRIMARY_AUDIO_ZONE, TEST_REAR_LEFT_ZONE_ID,
2589                          TEST_REAR_RIGHT_ZONE_ID, TEST_FRONT_ZONE_ID, TEST_REAR_ROW_3_ZONE_ID);
2590          expectWithMessage("Primary user id after server recovery")
2591                  .that(service.getUserIdForZone(PRIMARY_AUDIO_ZONE)).isEqualTo(TEST_DRIVER_USER_ID);
2592          expectWithMessage("Rear left user id after server recovery")
2593                  .that(service.getUserIdForZone(TEST_REAR_LEFT_ZONE_ID))
2594                  .isEqualTo(TEST_REAR_LEFT_USER_ID);
2595          expectWithMessage("Rear right user id after server recovery")
2596                  .that(service.getUserIdForZone(TEST_REAR_RIGHT_ZONE_ID))
2597                  .isEqualTo(TEST_REAR_RIGHT_USER_ID);
2598          expectWithMessage("Rear front user id after server recovery")
2599                  .that(service.getUserIdForZone(TEST_FRONT_ZONE_ID))
2600                  .isEqualTo(TEST_FRONT_PASSENGER_USER_ID);
2601          expectWithMessage("Rear row 3 user id after server recovery")
2602                  .that(service.getUserIdForZone(TEST_REAR_ROW_3_ZONE_ID))
2603                  .isEqualTo(TEST_REAR_ROW_3_PASSENGER_USER_ID);
2604      }
2605  
2606      @Test
registerVolumeCallback_verifyCallbackHandler()2607      public void registerVolumeCallback_verifyCallbackHandler() throws Exception {
2608          int uid = Binder.getCallingUid();
2609          CarAudioService service = setUpAudioService();
2610  
2611          service.registerVolumeCallback(mVolumeCallbackBinder);
2612  
2613          verify(mCarVolumeCallbackHandler).registerCallback(mVolumeCallbackBinder, uid, true);
2614      }
2615  
2616      @Test
unregisterVolumeCallback_verifyCallbackHandler()2617      public void unregisterVolumeCallback_verifyCallbackHandler() throws Exception {
2618          int uid = Binder.getCallingUid();
2619          CarAudioService service = setUpAudioService();
2620  
2621          service.unregisterVolumeCallback(mVolumeCallbackBinder);
2622  
2623          verify(mCarVolumeCallbackHandler).unregisterCallback(mVolumeCallbackBinder, uid);
2624      }
2625  
2626      @Test
getMutedVolumeGroups_forInvalidZone()2627      public void getMutedVolumeGroups_forInvalidZone() throws Exception {
2628          CarAudioService service = setUpAudioService();
2629  
2630          expectWithMessage("Muted volume groups for invalid zone")
2631                  .that(service.getMutedVolumeGroups(INVALID_AUDIO_ZONE))
2632                  .isEmpty();
2633      }
2634  
2635      @Test
getMutedVolumeGroups_whenVolumeGroupMuteNotSupported()2636      public void getMutedVolumeGroups_whenVolumeGroupMuteNotSupported() throws Exception {
2637          CarAudioService nonVolumeGroupMutingAudioService =
2638                  setUpAudioServiceWithDisabledResource(audioUseCarVolumeGroupMuting);
2639  
2640          expectWithMessage("Muted volume groups with disable mute feature")
2641                  .that(nonVolumeGroupMutingAudioService.getMutedVolumeGroups(PRIMARY_AUDIO_ZONE))
2642                  .isEmpty();
2643      }
2644  
2645      @Test
getMutedVolumeGroups_withMutedGroups()2646      public void getMutedVolumeGroups_withMutedGroups() throws Exception {
2647          CarAudioService service = setUpAudioService();
2648          service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
2649                  /* mute= */ true, TEST_FLAGS);
2650          service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_1,
2651                  /* mute= */ true, TEST_FLAGS);
2652  
2653          expectWithMessage("Muted volume groups")
2654                  .that(service.getMutedVolumeGroups(PRIMARY_AUDIO_ZONE))
2655                  .containsExactly(mTestPrimaryZoneVolumeInfo0,
2656                          mTestPrimaryZoneVolumeInfo1);
2657      }
2658  
2659      @Test
getMutedVolumeGroups_afterUnmuting()2660      public void getMutedVolumeGroups_afterUnmuting() throws Exception {
2661          CarAudioService service = setUpAudioService();
2662          service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
2663                  /* mute= */ true, TEST_FLAGS);
2664          service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_1,
2665                  /* mute= */ true, TEST_FLAGS);
2666          service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
2667                  /* mute= */ false, TEST_FLAGS);
2668  
2669          expectWithMessage("Muted volume groups after unmuting one group")
2670                  .that(service.getMutedVolumeGroups(PRIMARY_AUDIO_ZONE))
2671                  .containsExactly(mTestPrimaryZoneVolumeInfo1);
2672      }
2673  
2674      @Test
getMutedVolumeGroups_withMutedGroupsForDifferentZone()2675      public void getMutedVolumeGroups_withMutedGroupsForDifferentZone() throws Exception {
2676          CarAudioService service = setUpAudioService();
2677          service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
2678                  /* mute= */ true, TEST_FLAGS);
2679          service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_1,
2680                  /* mute= */ true, TEST_FLAGS);
2681  
2682          expectWithMessage("Muted volume groups for secondary zone")
2683                  .that(service.getMutedVolumeGroups(TEST_REAR_LEFT_ZONE_ID)).isEmpty();
2684      }
2685  
2686      @Test
onReceive_forLegacy_noCallToOnVolumeGroupChanged()2687      public void onReceive_forLegacy_noCallToOnVolumeGroupChanged() throws Exception {
2688          setUpAudioServiceWithoutDynamicRouting();
2689          mVolumeReceiverCaptor = ArgumentCaptor.forClass(BroadcastReceiver.class);
2690          verify(mMockContext).registerReceiver(mVolumeReceiverCaptor.capture(), any(), anyInt());
2691          BroadcastReceiver receiver = mVolumeReceiverCaptor.getValue();
2692          Intent intent = new Intent(VOLUME_CHANGED_ACTION);
2693  
2694          receiver.onReceive(mMockContext, intent);
2695  
2696          verify(mCarVolumeCallbackHandler, never())
2697                  .onVolumeGroupChange(anyInt(), anyInt(), anyInt());
2698      }
2699  
2700      @Test
onReceive_forLegacy_forStreamMusic()2701      public void onReceive_forLegacy_forStreamMusic() throws Exception {
2702          setUpAudioServiceWithoutDynamicRouting();
2703          verify(mMockContext).registerReceiver(mVolumeReceiverCaptor.capture(), any(), anyInt());
2704          BroadcastReceiver receiver = mVolumeReceiverCaptor.getValue();
2705          Intent intent = new Intent(VOLUME_CHANGED_ACTION)
2706                  .putExtra(EXTRA_VOLUME_STREAM_TYPE, STREAM_MUSIC);
2707  
2708          receiver.onReceive(mMockContext, intent);
2709  
2710          verify(mCarVolumeCallbackHandler).onVolumeGroupChange(
2711                  eq(PRIMARY_AUDIO_ZONE), anyInt(), eq(FLAG_FROM_KEY | FLAG_SHOW_UI));
2712      }
2713  
2714      @Test
onReceive_forLegacy_onMuteChanged()2715      public void onReceive_forLegacy_onMuteChanged() throws Exception {
2716          setUpAudioServiceWithoutDynamicRouting();
2717          ArgumentCaptor<BroadcastReceiver> captor =
2718                  ArgumentCaptor.forClass(BroadcastReceiver.class);
2719          verify(mMockContext).registerReceiver(captor.capture(), any(), anyInt());
2720          BroadcastReceiver receiver = captor.getValue();
2721          Intent intent = new Intent();
2722          intent.setAction(MASTER_MUTE_CHANGED_ACTION);
2723  
2724          receiver.onReceive(mMockContext, intent);
2725  
2726          verify(mCarVolumeCallbackHandler)
2727                  .onMasterMuteChanged(eq(PRIMARY_AUDIO_ZONE), eq(FLAG_FROM_KEY | FLAG_SHOW_UI));
2728      }
2729  
2730      @Test
getVolumeGroupInfosForZone()2731      public void getVolumeGroupInfosForZone() throws Exception {
2732          CarAudioService service = setUpAudioService();
2733          int groupCount = service.getVolumeGroupCount(PRIMARY_AUDIO_ZONE);
2734  
2735          List<CarVolumeGroupInfo> infos =
2736                  service.getVolumeGroupInfosForZone(PRIMARY_AUDIO_ZONE);
2737  
2738          for (int index = 0; index < groupCount; index++) {
2739              CarVolumeGroupInfo info = service
2740                      .getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, index);
2741              expectWithMessage("Car volume group infos for primary zone and info %s", info)
2742                      .that(infos).contains(info);
2743          }
2744      }
2745  
2746      @Test
getVolumeGroupInfosForZone_forDynamicRoutingDisabled()2747      public void getVolumeGroupInfosForZone_forDynamicRoutingDisabled() throws Exception {
2748          CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
2749  
2750          List<CarVolumeGroupInfo> infos =
2751                  nonDynamicAudioService.getVolumeGroupInfosForZone(PRIMARY_AUDIO_ZONE);
2752  
2753          expectWithMessage("Car volume group infos with dynamic routing disabled")
2754                  .that(infos).isEmpty();
2755      }
2756  
2757      @Test
getVolumeGroupInfosForZone_forOEMConfiguration()2758      public void getVolumeGroupInfosForZone_forOEMConfiguration() throws Exception {
2759          setUpTempFileForAudioConfiguration(R.raw.car_audio_configuration_using_oem_defined_context);
2760          CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext, mAudioManager,
2761                  mTempCarAudioConfigFile.getFile().getAbsolutePath(), mCarVolumeCallbackHandler,
2762                  /* audioFadeConfigurationPath= */ null);
2763          nonDynamicAudioService.init();
2764  
2765          List<CarVolumeGroupInfo> infos =
2766                  nonDynamicAudioService.getVolumeGroupInfosForZone(PRIMARY_AUDIO_ZONE);
2767  
2768          expectWithMessage("Car volume group infos size with OEM configuration")
2769                  .that(infos).hasSize(1);
2770          expectWithMessage("Car volume group info name with OEM configuration")
2771                  .that(infos.get(0).getName()).isEqualTo("OEM_VOLUME_GROUP");
2772      }
2773  
2774      @Test
getVolumeGroupInfosForZone_size()2775      public void getVolumeGroupInfosForZone_size() throws Exception {
2776          CarAudioService service = setUpAudioService();
2777          int groupCount = service.getVolumeGroupCount(PRIMARY_AUDIO_ZONE);
2778  
2779          List<CarVolumeGroupInfo> infos =
2780                  service.getVolumeGroupInfosForZone(PRIMARY_AUDIO_ZONE);
2781  
2782          expectWithMessage("Car volume group infos size for primary zone")
2783                  .that(infos).hasSize(groupCount);
2784      }
2785  
2786      @Test
getVolumeGroupInfosForZone_forInvalidZone()2787      public void getVolumeGroupInfosForZone_forInvalidZone() throws Exception {
2788          CarAudioService service = setUpAudioService();
2789  
2790          IllegalArgumentException thrown =
2791                  assertThrows(IllegalArgumentException.class, () ->
2792                          service.getVolumeGroupInfosForZone(INVALID_AUDIO_ZONE));
2793  
2794          expectWithMessage("Exception for volume group infos size for invalid zone")
2795                  .that(thrown).hasMessageThat().contains("audio zone Id");
2796      }
2797  
2798      @Test
getVolumeGroupInfo()2799      public void getVolumeGroupInfo() throws Exception {
2800          CarVolumeGroupInfo testVolumeGroupInfo = new CarVolumeGroupInfo.Builder(
2801                  mTestPrimaryZoneVolumeInfo0).setMuted(false).build();
2802          CarAudioService service = setUpAudioService();
2803  
2804          expectWithMessage("Car volume group info for primary zone")
2805                  .that(service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE,
2806                          TEST_PRIMARY_ZONE_GROUP_0)).isEqualTo(testVolumeGroupInfo);
2807      }
2808  
2809      @Test
getVolumeGroupInfo_forInvalidZone()2810      public void getVolumeGroupInfo_forInvalidZone() throws Exception {
2811          CarAudioService service = setUpAudioService();
2812  
2813          IllegalArgumentException thrown =
2814                  assertThrows(IllegalArgumentException.class, () ->
2815                          service.getVolumeGroupInfo(INVALID_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0));
2816  
2817          expectWithMessage("Exception for volume group info size for invalid zone")
2818                  .that(thrown).hasMessageThat().contains("audio zone Id");
2819      }
2820  
2821      @Test
getVolumeGroupInfo_forInvalidGroup()2822      public void getVolumeGroupInfo_forInvalidGroup() throws Exception {
2823          CarAudioService service = setUpAudioService();
2824  
2825          IllegalArgumentException thrown =
2826                  assertThrows(IllegalArgumentException.class, () ->
2827                          service.getVolumeGroupInfo(INVALID_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0));
2828  
2829          expectWithMessage("Exception for volume groups info size for invalid group id")
2830                  .that(thrown).hasMessageThat().contains("audio zone Id");
2831      }
2832  
2833      @Test
getVolumeGroupInfo_forGroupOverRange()2834      public void getVolumeGroupInfo_forGroupOverRange() throws Exception {
2835          CarAudioService service = setUpAudioService();
2836          int groupCount = service.getVolumeGroupCount(PRIMARY_AUDIO_ZONE);
2837  
2838          IllegalArgumentException thrown =
2839                  assertThrows(IllegalArgumentException.class, () ->
2840                          service.getVolumeGroupInfo(INVALID_AUDIO_ZONE,
2841                                  groupCount));
2842  
2843          expectWithMessage("Exception for volume groups info size for out of range group")
2844                  .that(thrown).hasMessageThat().contains("audio zone Id");
2845      }
2846  
2847      @Test
getVolumeGroupInfo_withLegacyMode()2848      public void getVolumeGroupInfo_withLegacyMode() throws Exception {
2849          CarAudioService service = setUpAudioServiceWithoutDynamicRouting();
2850  
2851          expectWithMessage("Volume group info in legacy mode")
2852                  .that(service.getVolumeGroupInfo(PRIMARY_OCCUPANT_ZONE, TEST_PRIMARY_ZONE_GROUP_0))
2853                  .isNull();
2854      }
2855  
2856      @Test
registerPrimaryZoneMediaAudioRequestCallbackListener_withNullCallback_fails()2857      public void registerPrimaryZoneMediaAudioRequestCallbackListener_withNullCallback_fails()
2858              throws Exception {
2859          CarAudioService service = setUpAudioService();
2860  
2861          NullPointerException thrown = assertThrows(NullPointerException.class, ()
2862                  -> service.registerPrimaryZoneMediaAudioRequestCallback(
2863                          /* callback= */ null));
2864  
2865          expectWithMessage("Register audio media request callback exception")
2866                  .that(thrown).hasMessageThat()
2867                  .contains("Media request callback");
2868      }
2869  
2870      @Test
unregisterPrimaryZoneMediaAudioRequestCallback_withNullCallback_fails()2871      public void unregisterPrimaryZoneMediaAudioRequestCallback_withNullCallback_fails()
2872              throws Exception {
2873          CarAudioService service = setUpAudioService();
2874  
2875          NullPointerException thrown = assertThrows(NullPointerException.class, ()
2876                  -> service.unregisterPrimaryZoneMediaAudioRequestCallback(
2877                          /* callback= */ null));
2878  
2879          expectWithMessage("Unregister audio media request callback exception")
2880                  .that(thrown).hasMessageThat()
2881                  .contains("Media request callback");
2882      }
2883  
2884      @Test
requestMediaAudioOnPrimaryZone_withPassengerOccupant_succeeds()2885      public void requestMediaAudioOnPrimaryZone_withPassengerOccupant_succeeds()
2886              throws Exception {
2887          CarAudioService service = setUpAudioService();
2888          TestPrimaryZoneMediaAudioRequestCallback
2889                  requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
2890          TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
2891          assignOccupantToAudioZones();
2892          service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
2893  
2894          expectWithMessage("Audio media request id")
2895                  .that(service.requestMediaAudioOnPrimaryZone(requestCallback,
2896                          TEST_REAR_RIGHT_PASSENGER_OCCUPANT))
2897                  .isNotEqualTo(INVALID_REQUEST_ID);
2898      }
2899  
2900      @Test
requestMediaAudioOnPrimaryZone_withDriverOccupant_fails()2901      public void requestMediaAudioOnPrimaryZone_withDriverOccupant_fails()
2902              throws Exception {
2903          CarAudioService service = setUpAudioService();
2904          TestPrimaryZoneMediaAudioRequestCallback
2905                  requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
2906          TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
2907          assignOccupantToAudioZones();
2908          service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
2909  
2910          IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, ()
2911                  -> service.requestMediaAudioOnPrimaryZone(requestCallback,
2912                  TEST_DRIVER_OCCUPANT));
2913  
2914          expectWithMessage("Request media audio exception")
2915                  .that(thrown).hasMessageThat().contains("already owns the primary audio zone");
2916      }
2917  
2918      @Test
requestMediaAudioOnPrimaryZone_withNonAssignedOccupant_fails()2919      public void requestMediaAudioOnPrimaryZone_withNonAssignedOccupant_fails()
2920              throws Exception {
2921          when(mMockOccupantZoneService.getAudioZoneIdForOccupant(TEST_UNASSIGNED_OCCUPANT_ZONE_ID))
2922                  .thenReturn(OUT_OF_RANGE_ZONE);
2923          CarAudioService service = setUpAudioService();
2924          TestPrimaryZoneMediaAudioRequestCallback
2925                  requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
2926          TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
2927          CarOccupantZoneManager.OccupantZoneInfo info =
2928                  getOccupantInfo(TEST_UNASSIGNED_OCCUPANT_ZONE_ID,
2929                  CarOccupantZoneManager.OCCUPANT_TYPE_DRIVER,
2930                  VehicleAreaSeat.SEAT_ROW_1_LEFT);
2931          assignOccupantToAudioZones();
2932          service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
2933  
2934          expectWithMessage("Invalid audio media request id")
2935                  .that(service.requestMediaAudioOnPrimaryZone(requestCallback, info))
2936                  .isEqualTo(INVALID_REQUEST_ID);
2937      }
2938  
2939      @Test
requestMediaAudioOnPrimaryZone_withPassengerOccupant_callsApprover()2940      public void requestMediaAudioOnPrimaryZone_withPassengerOccupant_callsApprover()
2941              throws Exception {
2942          CarAudioService service = setUpAudioService();
2943          TestPrimaryZoneMediaAudioRequestCallback
2944                  requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
2945          TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
2946          assignOccupantToAudioZones();
2947          service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
2948  
2949          long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
2950                  TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
2951  
2952          requestToken.waitForCallback();
2953          expectWithMessage("Called audio media request id")
2954                  .that(requestToken.mRequestId).isEqualTo(requestId);
2955          expectWithMessage("Called audio media request info")
2956                  .that(requestToken.mInfo).isEqualTo(TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
2957      }
2958  
2959      @Test
requestMediaAudioOnPrimaryZone_withZoneMirroring_fails()2960      public void requestMediaAudioOnPrimaryZone_withZoneMirroring_fails()
2961              throws Exception {
2962          CarAudioService service = setUpAudioService();
2963          TestPrimaryZoneMediaAudioRequestCallback
2964                  requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
2965          TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
2966          assignOccupantToAudioZones();
2967          service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
2968          TestAudioZonesMirrorStatusCallbackCallback mirrorCallback =
2969                  getAudioZonesMirrorStatusCallback(service);
2970          service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
2971          mirrorCallback.waitForCallback();
2972  
2973          IllegalStateException thrown = assertThrows(IllegalStateException.class, () ->
2974                          service.requestMediaAudioOnPrimaryZone(requestCallback,
2975                          TEST_REAR_RIGHT_PASSENGER_OCCUPANT));
2976  
2977          expectWithMessage("Request audio share while mirroring exception").that(thrown)
2978                  .hasMessageThat().contains("Can not request audio share to primary zone");
2979      }
2980  
2981      @Test
binderDied_onMediaRequestApprover_resetsApprovedRequest()2982      public void binderDied_onMediaRequestApprover_resetsApprovedRequest()
2983              throws Exception {
2984          CarAudioService service = setUpAudioService();
2985          TestPrimaryZoneMediaAudioRequestCallback requestToken =
2986                  new TestPrimaryZoneMediaAudioRequestCallback();
2987          TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
2988          assignOccupantToAudioZones();
2989          service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
2990          long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
2991                  TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
2992          requestToken.waitForCallback();
2993          requestToken.reset();
2994          service.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allow= */ true);
2995          requestToken.waitForCallback();
2996          requestCallback.waitForCallback();
2997          requestCallback.reset();
2998  
2999          requestToken.mDeathRecipient.binderDied();
3000  
3001          requestCallback.waitForCallback();
3002          expectWithMessage("Stopped status due to approver's death").that(requestCallback.mStatus)
3003                  .isEqualTo(CarAudioManager.AUDIO_REQUEST_STATUS_STOPPED);
3004          expectWithMessage("Stopped id due to approver's death")
3005                  .that(requestCallback.mRequestId).isEqualTo(requestId);
3006      }
3007  
3008      @Test
allowMediaAudioOnPrimaryZone_withAllowedRequest()3009      public void allowMediaAudioOnPrimaryZone_withAllowedRequest() throws Exception {
3010          CarAudioService service = setUpAudioService();
3011          TestPrimaryZoneMediaAudioRequestCallback
3012                  requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
3013          TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
3014          assignOccupantToAudioZones();
3015          service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
3016          long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
3017                  TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
3018          requestToken.waitForCallback();
3019  
3020          boolean results = service.allowMediaAudioOnPrimaryZone(requestToken, requestId,
3021                  /* allow= */ true);
3022  
3023          expectWithMessage("Allowed audio playback").that(results).isTrue();
3024      }
3025  
3026      @Test
allowMediaAudioOnPrimaryZone_whileMirroring_fails()3027      public void allowMediaAudioOnPrimaryZone_whileMirroring_fails() throws Exception {
3028          CarAudioService service = setUpAudioService();
3029          TestPrimaryZoneMediaAudioRequestCallback
3030                  requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
3031          TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
3032          assignOccupantToAudioZones();
3033          service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
3034          long shareId = service.requestMediaAudioOnPrimaryZone(requestCallback,
3035                  TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
3036          requestToken.waitForCallback();
3037          TestAudioZonesMirrorStatusCallbackCallback mirrorCallback =
3038                  getAudioZonesMirrorStatusCallback(service);
3039          service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
3040          mirrorCallback.waitForCallback();
3041          requestCallback.waitForCallback();
3042  
3043          IllegalStateException thrown =
3044                  assertThrows(IllegalStateException.class, () -> service
3045                          .allowMediaAudioOnPrimaryZone(requestToken, shareId, /* allow= */ true));
3046  
3047          expectWithMessage("Allow audio share while mirroring exception").that(thrown)
3048                  .hasMessageThat().contains("Can not allow audio share to primary zone");
3049          requestCallback.waitForCallback();
3050          expectWithMessage("Rejected status due to mirroring").that(requestCallback.mStatus)
3051                  .isEqualTo(CarAudioManager.AUDIO_REQUEST_STATUS_REJECTED);
3052          expectWithMessage("Rejected id with rejected due to mirroring")
3053                  .that(requestCallback.mRequestId).isEqualTo(shareId);
3054      }
3055  
3056      @Test
allowMediaAudioOnPrimaryZone_withUnallowedRequest()3057      public void allowMediaAudioOnPrimaryZone_withUnallowedRequest() throws Exception {
3058          CarAudioService service = setUpAudioService();
3059          TestPrimaryZoneMediaAudioRequestCallback
3060                  requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
3061          TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
3062          assignOccupantToAudioZones();
3063          service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
3064          long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
3065                  TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
3066          requestToken.waitForCallback();
3067  
3068          boolean results = service.allowMediaAudioOnPrimaryZone(requestToken, requestId,
3069                  /* allow= */ false);
3070  
3071          expectWithMessage("Unallowed audio playback").that(results).isTrue();
3072      }
3073  
3074      @Test
allowMediaAudioOnPrimaryZone_withAllowedRequest_callsRequester()3075      public void allowMediaAudioOnPrimaryZone_withAllowedRequest_callsRequester() throws Exception {
3076          CarAudioService service = setUpAudioService();
3077          TestPrimaryZoneMediaAudioRequestCallback
3078                  requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
3079          TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
3080          assignOccupantToAudioZones();
3081          service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
3082          long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
3083                  TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
3084          requestToken.waitForCallback();
3085  
3086          service.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allow= */ true);
3087  
3088          requestCallback.waitForCallback();
3089          expectWithMessage("Media request called audio media request id")
3090                  .that(requestCallback.mRequestId).isEqualTo(requestId);
3091          expectWithMessage("Media request called audio media request info")
3092                  .that(requestCallback.mInfo).isEqualTo(TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
3093          expectWithMessage("Media request called audio media request status")
3094                  .that(requestCallback.mStatus)
3095                  .isEqualTo(CarAudioManager.AUDIO_REQUEST_STATUS_APPROVED);
3096      }
3097  
3098      @Test
allowMediaAudioOnPrimaryZone_withAllowedRequest_callsApprover()3099      public void allowMediaAudioOnPrimaryZone_withAllowedRequest_callsApprover() throws Exception {
3100          CarAudioService service = setUpAudioService();
3101          TestPrimaryZoneMediaAudioRequestCallback
3102                  requestApprover = new TestPrimaryZoneMediaAudioRequestCallback();
3103          TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
3104          assignOccupantToAudioZones();
3105          service.registerPrimaryZoneMediaAudioRequestCallback(requestApprover);
3106          long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
3107                  TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
3108          requestApprover.waitForCallback();
3109          requestApprover.reset();
3110  
3111          service.allowMediaAudioOnPrimaryZone(requestApprover, requestId, /* allow= */ true);
3112  
3113          requestApprover.waitForCallback();
3114          expectWithMessage("Media approver called audio media request id")
3115                  .that(requestApprover.mRequestId).isEqualTo(requestId);
3116          expectWithMessage("Media approver called audio media request info")
3117                  .that(requestApprover.mInfo).isEqualTo(TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
3118          expectWithMessage("Media approver called audio media request status")
3119                  .that(requestApprover.mStatus)
3120                  .isEqualTo(CarAudioManager.AUDIO_REQUEST_STATUS_APPROVED);
3121      }
3122  
3123      @Test
allowMediaAudioOnPrimaryZone_withUnallowedRequest_callsRequester()3124      public void allowMediaAudioOnPrimaryZone_withUnallowedRequest_callsRequester()
3125              throws Exception {
3126          CarAudioService service = setUpAudioService();
3127          TestPrimaryZoneMediaAudioRequestCallback
3128                  requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
3129          TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
3130          assignOccupantToAudioZones();
3131          service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
3132          long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
3133                  TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
3134          requestToken.waitForCallback();
3135  
3136          service.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allow= */ false);
3137  
3138          requestCallback.waitForCallback();
3139          expectWithMessage("Unallowed media request called audio media request id")
3140                  .that(requestCallback.mRequestId).isEqualTo(requestId);
3141          expectWithMessage("Unallowed media request called audio media request info")
3142                  .that(requestCallback.mInfo).isEqualTo(TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
3143          expectWithMessage("Unallowed media request called audio media request status")
3144                  .that(requestCallback.mStatus)
3145                  .isEqualTo(CarAudioManager.AUDIO_REQUEST_STATUS_REJECTED);
3146      }
3147  
3148      @Test
allowMediaAudioOnPrimaryZone_withUnallowedRequest_callsApprover()3149      public void allowMediaAudioOnPrimaryZone_withUnallowedRequest_callsApprover() throws Exception {
3150          CarAudioService service = setUpAudioService();
3151          TestPrimaryZoneMediaAudioRequestCallback
3152                  requestApprover = new TestPrimaryZoneMediaAudioRequestCallback();
3153          TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
3154          assignOccupantToAudioZones();
3155          service.registerPrimaryZoneMediaAudioRequestCallback(requestApprover);
3156          long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
3157                  TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
3158          requestApprover.waitForCallback();
3159          requestApprover.reset();
3160  
3161          service.allowMediaAudioOnPrimaryZone(requestApprover, requestId, /* allow= */ false);
3162  
3163          requestApprover.waitForCallback();
3164          expectWithMessage("Unallowed media approver called audio media request id")
3165                  .that(requestApprover.mRequestId).isEqualTo(requestId);
3166          expectWithMessage("Unallowed approver token called audio media request info")
3167                  .that(requestApprover.mInfo).isEqualTo(TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
3168          expectWithMessage("Unallowed approver token called audio media request status")
3169                  .that(requestApprover.mStatus)
3170                  .isEqualTo(CarAudioManager.AUDIO_REQUEST_STATUS_REJECTED);
3171      }
3172  
3173      @Test
isMediaAudioAllowedInPrimaryZone_witNullOccupant_fails()3174      public void isMediaAudioAllowedInPrimaryZone_witNullOccupant_fails() throws Exception {
3175          CarAudioService service = setUpAudioService();
3176          NullPointerException thrown = assertThrows(NullPointerException.class, ()
3177                  -> service.isMediaAudioAllowedInPrimaryZone(/* info= */ null));
3178  
3179          expectWithMessage("Media status exception").that(thrown)
3180                  .hasMessageThat().contains("Occupant zone info");
3181      }
3182  
3183      @Test
isMediaAudioAllowedInPrimaryZone_byDefault()3184      public void isMediaAudioAllowedInPrimaryZone_byDefault() throws Exception {
3185          CarAudioService service = setUpAudioService();
3186  
3187          expectWithMessage("Media default status")
3188                  .that(service.isMediaAudioAllowedInPrimaryZone(
3189                          TEST_REAR_RIGHT_PASSENGER_OCCUPANT))
3190                  .isFalse();
3191      }
3192  
3193      @Test
isMediaAudioAllowedInPrimaryZone_afterAllowed()3194      public void isMediaAudioAllowedInPrimaryZone_afterAllowed() throws Exception {
3195          CarAudioService service = setUpAudioService();
3196          TestPrimaryZoneMediaAudioRequestCallback
3197                  requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
3198          TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
3199          assignOccupantToAudioZones();
3200          service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
3201          long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
3202                  TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
3203          requestToken.waitForCallback();
3204          requestToken.reset();
3205          service.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allow= */ true);
3206          requestToken.waitForCallback();
3207  
3208          expectWithMessage("Media allowed status")
3209                  .that(service.isMediaAudioAllowedInPrimaryZone(
3210                          TEST_REAR_RIGHT_PASSENGER_OCCUPANT))
3211                  .isTrue();
3212      }
3213  
3214      @Test
isMediaAudioAllowedInPrimaryZone_afterDisallowed()3215      public void isMediaAudioAllowedInPrimaryZone_afterDisallowed() throws Exception {
3216          CarAudioService service = setUpAudioService();
3217          TestPrimaryZoneMediaAudioRequestCallback
3218                  requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
3219          TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
3220          assignOccupantToAudioZones();
3221          service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
3222          long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
3223                  TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
3224          requestToken.waitForCallback();
3225          requestToken.reset();
3226          service.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allow= */ false);
3227          requestToken.waitForCallback();
3228  
3229          expectWithMessage("Media after disallowed status")
3230                  .that(service.isMediaAudioAllowedInPrimaryZone(
3231                          TEST_REAR_RIGHT_PASSENGER_OCCUPANT))
3232                  .isFalse();
3233      }
3234  
3235      @Test
isMediaAudioAllowedInPrimaryZone_afterUserLogout()3236      public void isMediaAudioAllowedInPrimaryZone_afterUserLogout() throws Exception {
3237          CarAudioService service = setUpAudioService();
3238          TestPrimaryZoneMediaAudioRequestCallback
3239                  requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
3240          TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
3241          assignOccupantToAudioZones();
3242          service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
3243          long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
3244                  TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
3245          requestToken.waitForCallback();
3246          requestToken.reset();
3247          service.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allow= */ true);
3248          requestToken.waitForCallback();
3249          requestToken.reset();
3250          simulateLogoutPassengers();
3251          requestToken.waitForCallback();
3252  
3253          expectWithMessage("Media allowed status after passenger logout")
3254                  .that(service.isMediaAudioAllowedInPrimaryZone(
3255                          TEST_REAR_RIGHT_PASSENGER_OCCUPANT)).isFalse();
3256      }
3257  
3258      @Test
isMediaAudioAllowedInPrimaryZone_afterUserSwitch()3259      public void isMediaAudioAllowedInPrimaryZone_afterUserSwitch() throws Exception {
3260          CarAudioService service = setUpAudioService();
3261          TestPrimaryZoneMediaAudioRequestCallback
3262                  requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
3263          TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
3264          assignOccupantToAudioZones();
3265          service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
3266          long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
3267                  TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
3268          requestToken.waitForCallback();
3269          requestToken.reset();
3270          service.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allow= */ true);
3271          requestToken.waitForCallback();
3272          requestToken.reset();
3273          simulatePassengersSwitch();
3274          requestToken.waitForCallback();
3275  
3276          expectWithMessage("Media allowed status after passenger switch")
3277                  .that(service.isMediaAudioAllowedInPrimaryZone(
3278                          TEST_REAR_RIGHT_PASSENGER_OCCUPANT)).isFalse();
3279      }
3280  
3281      @Test
resetMediaAudioOnPrimaryZone_afterAllowed()3282      public void resetMediaAudioOnPrimaryZone_afterAllowed() throws Exception {
3283          CarAudioService service = setUpAudioService();
3284          TestPrimaryZoneMediaAudioRequestCallback
3285                  requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
3286          TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
3287          assignOccupantToAudioZones();
3288          service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
3289          long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
3290                  TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
3291          requestToken.waitForCallback();
3292          requestToken.reset();
3293          service.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allow= */ true);
3294          requestToken.waitForCallback();
3295          requestToken.reset();
3296  
3297          boolean reset = service.resetMediaAudioOnPrimaryZone(
3298                  TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
3299  
3300          requestToken.waitForCallback();
3301          expectWithMessage("Reset status").that(reset).isTrue();
3302          expectWithMessage("Media reset status")
3303                  .that(service.isMediaAudioAllowedInPrimaryZone(
3304                          TEST_REAR_RIGHT_PASSENGER_OCCUPANT))
3305                  .isFalse();
3306      }
3307  
3308      @Test
cancelMediaAudioOnPrimaryZone_beforeAllowed()3309      public void cancelMediaAudioOnPrimaryZone_beforeAllowed() throws Exception {
3310          CarAudioService service = setUpAudioService();
3311          TestPrimaryZoneMediaAudioRequestCallback
3312                  requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
3313          TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
3314          assignOccupantToAudioZones();
3315          service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
3316          long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
3317                  TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
3318          requestToken.waitForCallback();
3319          requestToken.reset();
3320  
3321          boolean cancel = service.cancelMediaAudioOnPrimaryZone(requestId);
3322  
3323          requestToken.waitForCallback();
3324          expectWithMessage("Cancel status").that(cancel).isTrue();
3325          expectWithMessage("Canceled media token called audio media request id")
3326                  .that(requestToken.mRequestId).isEqualTo(requestId);
3327          expectWithMessage("Canceled media token called audio media request info")
3328                  .that(requestToken.mInfo).isEqualTo(TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
3329          expectWithMessage("Canceled media token called audio media request status")
3330                  .that(requestToken.mStatus)
3331                  .isEqualTo(CarAudioManager.AUDIO_REQUEST_STATUS_CANCELLED);
3332      }
3333  
3334      @Test
cancelMediaAudioOnPrimaryZone_afterAllowed()3335      public void cancelMediaAudioOnPrimaryZone_afterAllowed() throws Exception {
3336          CarAudioService service = setUpAudioService();
3337          TestPrimaryZoneMediaAudioRequestCallback
3338                  requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
3339          TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
3340          assignOccupantToAudioZones();
3341          service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
3342          long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
3343                  TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
3344          requestToken.waitForCallback();
3345          requestToken.reset();
3346          service.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allow= */ true);
3347          requestToken.waitForCallback();
3348          requestToken.reset();
3349  
3350          boolean cancel = service.cancelMediaAudioOnPrimaryZone(requestId);
3351  
3352          requestToken.waitForCallback();
3353          expectWithMessage("Cancel status after allowed").that(cancel).isTrue();
3354          expectWithMessage("Media allowed status after canceled")
3355                  .that(service.isMediaAudioAllowedInPrimaryZone(
3356                          TEST_REAR_RIGHT_PASSENGER_OCCUPANT))
3357                  .isFalse();
3358      }
3359  
3360      @Test
getZoneIdForAudioFocusInfo_beforeAllowedSharedAudio()3361      public void getZoneIdForAudioFocusInfo_beforeAllowedSharedAudio() throws Exception {
3362          CarAudioService service = setUpAudioService();
3363          TestPrimaryZoneMediaAudioRequestCallback
3364                  requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
3365          TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
3366          assignOccupantToAudioZones();
3367          service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
3368          service.requestMediaAudioOnPrimaryZone(requestCallback,
3369                  TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
3370          requestToken.waitForCallback();
3371  
3372          expectWithMessage("Not yet shared media user zone")
3373                  .that(service.getZoneIdForAudioFocusInfo(TEST_REAR_RIGHT_AUDIO_FOCUS_INFO))
3374                  .isEqualTo(TEST_REAR_RIGHT_ZONE_ID);
3375      }
3376  
3377      @Test
getZoneIdForAudioFocusInfo_afterAllowedShareAudio()3378      public void getZoneIdForAudioFocusInfo_afterAllowedShareAudio() throws Exception {
3379          CarAudioService service = setUpAudioService();
3380          TestPrimaryZoneMediaAudioRequestCallback
3381                  requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
3382          TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
3383          assignOccupantToAudioZones();
3384          service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
3385          long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
3386                  TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
3387          requestToken.waitForCallback();
3388          requestToken.reset();
3389          service.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allow= */ true);
3390          requestToken.waitForCallback();
3391  
3392          expectWithMessage("Shared media user zone")
3393                  .that(service.getZoneIdForAudioFocusInfo(TEST_REAR_RIGHT_AUDIO_FOCUS_INFO))
3394                  .isEqualTo(PRIMARY_AUDIO_ZONE);
3395      }
3396  
3397      @Test
getZoneIdForAudioFocusInfo_afterCanceled()3398      public void getZoneIdForAudioFocusInfo_afterCanceled() throws Exception {
3399          CarAudioService service = setUpAudioService();
3400          TestPrimaryZoneMediaAudioRequestCallback
3401                  requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
3402          TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
3403          assignOccupantToAudioZones();
3404          service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
3405          long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
3406                  TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
3407          requestToken.waitForCallback();
3408          requestToken.reset();
3409          service.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allow= */ true);
3410          requestToken.waitForCallback();
3411          requestToken.reset();
3412          service.cancelMediaAudioOnPrimaryZone(requestId);
3413          requestToken.waitForCallback();
3414  
3415          expectWithMessage("Canceled shared media user zone")
3416                  .that(service.getZoneIdForAudioFocusInfo(TEST_REAR_RIGHT_AUDIO_FOCUS_INFO))
3417                  .isEqualTo(TEST_REAR_RIGHT_ZONE_ID);
3418      }
3419  
3420      @Test
getZoneIdForAudioFocusInfo_afterReset()3421      public void getZoneIdForAudioFocusInfo_afterReset() throws Exception {
3422          CarAudioService service = setUpAudioService();
3423          TestPrimaryZoneMediaAudioRequestCallback
3424                  requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
3425          TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
3426          assignOccupantToAudioZones();
3427          service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
3428          long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
3429                  TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
3430          requestToken.waitForCallback();
3431          requestToken.reset();
3432          service.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allow= */ true);
3433          requestToken.waitForCallback();
3434          requestToken.reset();
3435          service.resetMediaAudioOnPrimaryZone(TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
3436          requestToken.waitForCallback();
3437  
3438          expectWithMessage("Reset shared media user zone")
3439                  .that(service.getZoneIdForAudioFocusInfo(TEST_REAR_RIGHT_AUDIO_FOCUS_INFO))
3440                  .isEqualTo(TEST_REAR_RIGHT_ZONE_ID);
3441      }
3442  
getOccupantInfo(int occupantZoneId, int occupantType, int seat)3443      private static CarOccupantZoneManager.OccupantZoneInfo getOccupantInfo(int occupantZoneId,
3444              int occupantType, int seat) {
3445          return new CarOccupantZoneManager.OccupantZoneInfo(occupantZoneId, occupantType, seat);
3446      }
3447  
3448      @Test
getAudioAttributesForVolumeGroup()3449      public void getAudioAttributesForVolumeGroup() throws Exception {
3450          CarAudioService service = setUpAudioService();
3451          CarVolumeGroupInfo info = service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE,
3452                  TEST_PRIMARY_ZONE_GROUP_0);
3453  
3454          List<AudioAttributes> audioAttributes =
3455                  service.getAudioAttributesForVolumeGroup(info);
3456  
3457          expectWithMessage("Volume group audio attributes").that(audioAttributes)
3458                  .containsExactly(
3459                          CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA),
3460                          CarAudioContext.getAudioAttributeFromUsage(USAGE_GAME),
3461                          CarAudioContext.getAudioAttributeFromUsage(USAGE_UNKNOWN),
3462                          CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION),
3463                          CarAudioContext.getAudioAttributeFromUsage(USAGE_NOTIFICATION_EVENT),
3464                          CarAudioContext.getAudioAttributeFromUsage(USAGE_ANNOUNCEMENT));
3465      }
3466  
3467      @Test
getAudioAttributesForVolumeGroup_withNullInfo_fails()3468      public void getAudioAttributesForVolumeGroup_withNullInfo_fails() throws Exception {
3469          CarAudioService service = setUpAudioService();
3470  
3471          NullPointerException thrown =
3472                  assertThrows(NullPointerException.class, () ->
3473                          service.getAudioAttributesForVolumeGroup(/* groupInfo= */ null));
3474  
3475          expectWithMessage("Volume group audio attributes with null info exception")
3476                  .that(thrown).hasMessageThat().contains("Car volume group info");
3477      }
3478  
3479      @Test
getAudioAttributesForVolumeGroup_withDynamicRoutingDisabled()3480      public void getAudioAttributesForVolumeGroup_withDynamicRoutingDisabled() throws Exception {
3481          CarAudioService nonDynamicAudioService = setUpAudioServiceWithoutDynamicRouting();
3482  
3483          List<AudioAttributes> audioAttributes = nonDynamicAudioService
3484                  .getAudioAttributesForVolumeGroup(mTestPrimaryZoneVolumeInfo0);
3485  
3486          expectWithMessage("Volume group audio attributes with dynamic routing disabled")
3487                  .that(audioAttributes).isEmpty();
3488      }
3489  
3490      @Test
onKeyEvent_forInvalidAudioZone()3491      public void onKeyEvent_forInvalidAudioZone() throws Exception {
3492          CarAudioService service = setUpAudioService();
3493          int volumeBefore = service.getGroupVolume(PRIMARY_AUDIO_ZONE,
3494                  TEST_PRIMARY_ZONE_GROUP_0);
3495          KeyEventListener listener = getAudioKeyEventListener();
3496          when(mMockOccupantZoneService.getOccupantZoneIdForSeat(TEST_SEAT))
3497                  .thenReturn(PRIMARY_OCCUPANT_ZONE);
3498          when(mMockOccupantZoneService.getAudioZoneIdForOccupant(PRIMARY_OCCUPANT_ZONE))
3499                  .thenReturn(INVALID_AUDIO_ZONE);
3500          KeyEvent keyEvent = new KeyEvent(ACTION_DOWN, KEYCODE_UNKNOWN);
3501  
3502          listener.onKeyEvent(keyEvent, TEST_DISPLAY_TYPE, TEST_SEAT);
3503  
3504          expectWithMessage("Volume group volume after invalid audio zone")
3505                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
3506                          TEST_PRIMARY_ZONE_GROUP_0)).isEqualTo(volumeBefore);
3507      }
3508  
3509      @Test
onKeyEvent_forInvalidEvent()3510      public void onKeyEvent_forInvalidEvent() throws Exception {
3511          CarAudioService service = setUpAudioService();
3512          int volumeBefore = service.getGroupVolume(PRIMARY_AUDIO_ZONE,
3513                  TEST_PRIMARY_ZONE_GROUP_0);
3514          KeyEventListener listener = getAudioKeyEventListener();
3515          when(mMockOccupantZoneService.getOccupantZoneIdForSeat(TEST_SEAT))
3516                  .thenReturn(PRIMARY_OCCUPANT_ZONE);
3517          when(mMockOccupantZoneService.getAudioZoneIdForOccupant(PRIMARY_OCCUPANT_ZONE))
3518                  .thenReturn(PRIMARY_AUDIO_ZONE);
3519          KeyEvent keyEvent = new KeyEvent(ACTION_DOWN, KEYCODE_UNKNOWN);
3520  
3521          listener.onKeyEvent(keyEvent, TEST_DISPLAY_TYPE, TEST_SEAT);
3522  
3523          expectWithMessage("Volume group volume after unknown key event")
3524                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
3525                          TEST_PRIMARY_ZONE_GROUP_0)).isEqualTo(volumeBefore);
3526      }
3527  
3528      @Test
onKeyEvent_forActionUp()3529      public void onKeyEvent_forActionUp() throws Exception {
3530          CarAudioService service = setUpAudioService();
3531          int volumeBefore = service.getGroupVolume(PRIMARY_AUDIO_ZONE,
3532                  TEST_PRIMARY_ZONE_GROUP_0);
3533          KeyEventListener listener = getAudioKeyEventListener();
3534          when(mMockOccupantZoneService.getOccupantZoneIdForSeat(TEST_SEAT))
3535                  .thenReturn(PRIMARY_OCCUPANT_ZONE);
3536          when(mMockOccupantZoneService.getAudioZoneIdForOccupant(PRIMARY_OCCUPANT_ZONE))
3537                  .thenReturn(PRIMARY_AUDIO_ZONE);
3538          KeyEvent keyEvent = new KeyEvent(ACTION_UP, KEYCODE_VOLUME_UP);
3539  
3540          listener.onKeyEvent(keyEvent, TEST_DISPLAY_TYPE, TEST_SEAT);
3541  
3542          expectWithMessage("Volume group volume after volume up in primary zone in primary group "
3543                  + "for action up")
3544                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
3545                          TEST_PRIMARY_ZONE_GROUP_0)).isEqualTo(volumeBefore);
3546      }
3547  
3548      @Test
onKeyEvent_forDynamicDevKeyEventEnabledForDefaultConfigForZoneWithDynamicDevices()3549      public void onKeyEvent_forDynamicDevKeyEventEnabledForDefaultConfigForZoneWithDynamicDevices()
3550              throws Exception {
3551          enableVolumeKeyEventsToDynamicDevices(/* enableVolumeKeyEvents= */ true);
3552          CarAudioService service = setUpAudioServiceWithDynamicDevices();
3553          service.init();
3554          assignOccupantToAudioZones();
3555          int volumeBefore = service.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0);
3556          KeyEventListener listener = getAudioKeyEventListener();
3557          when(mMockOccupantZoneService.getOccupantZoneIdForSeat(TEST_SEAT))
3558                  .thenReturn(PRIMARY_OCCUPANT_ZONE);
3559          when(mMockOccupantZoneService.getAudioZoneIdForOccupant(PRIMARY_OCCUPANT_ZONE))
3560                  .thenReturn(PRIMARY_AUDIO_ZONE);
3561          KeyEvent actionDownKeyEvent = new KeyEvent(ACTION_DOWN, KEYCODE_VOLUME_UP);
3562          KeyEvent actionUpKeyEvent = new KeyEvent(ACTION_UP, KEYCODE_VOLUME_UP);
3563          listener.onKeyEvent(actionDownKeyEvent, TEST_DISPLAY_TYPE, TEST_SEAT);
3564  
3565          listener.onKeyEvent(actionUpKeyEvent, TEST_DISPLAY_TYPE, TEST_SEAT);
3566  
3567          expectWithMessage("Volume group volume after volume up in primary zone in primary group "
3568                  + "for volume group without dynamic devices")
3569                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0))
3570                  .isEqualTo(volumeBefore + 1);
3571      }
3572  
3573      @Test
3574      public void
onKeyEvent_forDynamicDevKeyEventEnabledForDynamicDeviceConfigForZoneWithDynamicDevices()3575              onKeyEvent_forDynamicDevKeyEventEnabledForDynamicDeviceConfigForZoneWithDynamicDevices()
3576              throws Exception {
3577          enableVolumeKeyEventsToDynamicDevices(/* enableVolumeKeyEvents= */ true);
3578          CarAudioService service = setUpAudioServiceWithDynamicDevices();
3579          service.init();
3580          assignOccupantToAudioZones();
3581          SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl();
3582          TestAudioZoneConfigurationsChangeCallback configCallback =
3583                  getRegisteredZoneConfigCallback(service);
3584          AudioDeviceCallback deviceCallback = captureAudioDeviceCallback();
3585          deviceCallback.onAudioDevicesAdded(new AudioDeviceInfo[]{mBTAudioDeviceInfo});
3586          configCallback.waitForCallback();
3587          configCallback.reset();
3588          List<CarAudioZoneConfigInfo> zoneConfigInfos =
3589                  service.getAudioZoneConfigInfos(PRIMARY_AUDIO_ZONE);
3590          CarAudioZoneConfigInfo zoneConfigSwitchTo = zoneConfigInfos.stream()
3591                  .filter(c -> c.getName().equals(PRIMARY_CONFIG_NAME_DYNAMIC_DEVICES))
3592                  .findFirst().orElseThrow();
3593          service.switchZoneToConfig(zoneConfigSwitchTo, callback);
3594          configCallback.waitForCallback();
3595          int volumeBefore = service.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0);
3596          KeyEventListener listener = getAudioKeyEventListener();
3597          when(mMockOccupantZoneService.getOccupantZoneIdForSeat(TEST_SEAT))
3598                  .thenReturn(PRIMARY_OCCUPANT_ZONE);
3599          when(mMockOccupantZoneService.getAudioZoneIdForOccupant(PRIMARY_OCCUPANT_ZONE))
3600                  .thenReturn(PRIMARY_AUDIO_ZONE);
3601          KeyEvent actionDownKeyEvent = new KeyEvent(ACTION_DOWN, KEYCODE_VOLUME_UP);
3602          KeyEvent actionUpKeyEvent = new KeyEvent(ACTION_UP, KEYCODE_VOLUME_UP);
3603          listener.onKeyEvent(actionDownKeyEvent, TEST_DISPLAY_TYPE, TEST_SEAT);
3604  
3605          listener.onKeyEvent(actionUpKeyEvent, TEST_DISPLAY_TYPE, TEST_SEAT);
3606  
3607          expectWithMessage("Volume after volume up in primary zone in primary group "
3608                  + "for volume group with dynamic devices while dynamic device key events enabled")
3609                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0))
3610                  .isEqualTo(volumeBefore + 1);
3611      }
3612  
3613      @Test
3614      public void
onKeyEvent_forDynDevKeyEventDisabledForDynamicDeviceConfigForZoneWithDynamicDevices()3615              onKeyEvent_forDynDevKeyEventDisabledForDynamicDeviceConfigForZoneWithDynamicDevices()
3616              throws Exception {
3617          enableVolumeKeyEventsToDynamicDevices(/* enableVolumeKeyEvents= */ false);
3618          CarAudioService service = setUpAudioServiceWithDynamicDevices();
3619          service.init();
3620          assignOccupantToAudioZones();
3621          SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl();
3622          TestAudioZoneConfigurationsChangeCallback configCallback =
3623                  getRegisteredZoneConfigCallback(service);
3624          AudioDeviceCallback deviceCallback = captureAudioDeviceCallback();
3625          deviceCallback.onAudioDevicesAdded(new AudioDeviceInfo[]{mBTAudioDeviceInfo});
3626          configCallback.waitForCallback();
3627          configCallback.reset();
3628          List<CarAudioZoneConfigInfo> zoneConfigInfos =
3629                  service.getAudioZoneConfigInfos(PRIMARY_AUDIO_ZONE);
3630          CarAudioZoneConfigInfo zoneConfigSwitchTo = zoneConfigInfos.stream()
3631                  .filter(c -> c.getName().equals(PRIMARY_CONFIG_NAME_DYNAMIC_DEVICES))
3632                  .findFirst().orElseThrow();
3633          service.switchZoneToConfig(zoneConfigSwitchTo, callback);
3634          configCallback.waitForCallback();
3635          int volumeBefore = service.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0);
3636          KeyEventListener listener = getAudioKeyEventListener();
3637          when(mMockOccupantZoneService.getOccupantZoneIdForSeat(TEST_SEAT))
3638                  .thenReturn(PRIMARY_OCCUPANT_ZONE);
3639          when(mMockOccupantZoneService.getAudioZoneIdForOccupant(PRIMARY_OCCUPANT_ZONE))
3640                  .thenReturn(PRIMARY_AUDIO_ZONE);
3641          KeyEvent actionDownKeyEvent = new KeyEvent(ACTION_DOWN, KEYCODE_VOLUME_UP);
3642          KeyEvent actionUpKeyEvent = new KeyEvent(ACTION_UP, KEYCODE_VOLUME_UP);
3643          listener.onKeyEvent(actionDownKeyEvent, TEST_DISPLAY_TYPE, TEST_SEAT);
3644  
3645          listener.onKeyEvent(actionUpKeyEvent, TEST_DISPLAY_TYPE, TEST_SEAT);
3646  
3647          expectWithMessage("Volume after volume up in primary zone in primary group "
3648                  + "for volume group with dynamic devices while dynamic device key events disabled")
3649                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0))
3650                  .isEqualTo(volumeBefore);
3651      }
3652  
3653      @Test
onKeyEvent_forActionDownFollowedByActionUp()3654      public void onKeyEvent_forActionDownFollowedByActionUp() throws Exception {
3655          CarAudioService service = setUpAudioService();
3656          int volumeBefore = service.getGroupVolume(PRIMARY_AUDIO_ZONE,
3657                  TEST_PRIMARY_ZONE_GROUP_0);
3658          KeyEventListener listener = getAudioKeyEventListener();
3659          when(mMockOccupantZoneService.getOccupantZoneIdForSeat(TEST_SEAT))
3660                  .thenReturn(PRIMARY_OCCUPANT_ZONE);
3661          when(mMockOccupantZoneService.getAudioZoneIdForOccupant(PRIMARY_OCCUPANT_ZONE))
3662                  .thenReturn(PRIMARY_AUDIO_ZONE);
3663          KeyEvent actionDownKeyEvent = new KeyEvent(ACTION_DOWN, KEYCODE_VOLUME_UP);
3664          KeyEvent actionUpKeyEvent = new KeyEvent(ACTION_UP, KEYCODE_VOLUME_UP);
3665          listener.onKeyEvent(actionDownKeyEvent, TEST_DISPLAY_TYPE, TEST_SEAT);
3666  
3667          listener.onKeyEvent(actionUpKeyEvent, TEST_DISPLAY_TYPE, TEST_SEAT);
3668  
3669          expectWithMessage("Volume group volume after volume up in primary zone in primary group "
3670                  + "for action down then action up")
3671                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
3672                          TEST_PRIMARY_ZONE_GROUP_0)).isEqualTo(volumeBefore + 1);
3673      }
3674  
3675      @Test
onKeyEvent_forVolumeUpEvent_inPrimaryZone()3676      public void onKeyEvent_forVolumeUpEvent_inPrimaryZone() throws Exception {
3677          CarAudioService service = setUpAudioService();
3678          int volumeBefore = service.getGroupVolume(PRIMARY_AUDIO_ZONE,
3679                  TEST_PRIMARY_ZONE_GROUP_0);
3680          KeyEventListener listener = getAudioKeyEventListener();
3681          when(mMockOccupantZoneService.getOccupantZoneIdForSeat(TEST_SEAT))
3682                  .thenReturn(PRIMARY_OCCUPANT_ZONE);
3683          when(mMockOccupantZoneService.getAudioZoneIdForOccupant(PRIMARY_OCCUPANT_ZONE))
3684                  .thenReturn(PRIMARY_AUDIO_ZONE);
3685          KeyEvent keyEvent = new KeyEvent(ACTION_DOWN, KEYCODE_VOLUME_UP);
3686  
3687          listener.onKeyEvent(keyEvent, TEST_DISPLAY_TYPE, TEST_SEAT);
3688  
3689          expectWithMessage("Volume group volume after volume up in primary zone in primary group")
3690                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
3691                          TEST_PRIMARY_ZONE_GROUP_0)).isGreaterThan(volumeBefore);
3692      }
3693  
3694      @Test
onKeyEvent_forVolumeDownEvent_inPrimaryZone()3695      public void onKeyEvent_forVolumeDownEvent_inPrimaryZone() throws Exception {
3696          CarAudioService service = setUpAudioService();
3697          int volumeBefore = service.getGroupVolume(PRIMARY_AUDIO_ZONE,
3698                  TEST_PRIMARY_ZONE_GROUP_0);
3699          KeyEventListener listener = getAudioKeyEventListener();
3700          when(mMockOccupantZoneService.getOccupantZoneIdForSeat(TEST_SEAT))
3701                  .thenReturn(PRIMARY_OCCUPANT_ZONE);
3702          when(mMockOccupantZoneService.getAudioZoneIdForOccupant(PRIMARY_OCCUPANT_ZONE))
3703                  .thenReturn(PRIMARY_AUDIO_ZONE);
3704          KeyEvent keyEvent = new KeyEvent(ACTION_DOWN, KEYCODE_VOLUME_DOWN);
3705  
3706          listener.onKeyEvent(keyEvent, TEST_DISPLAY_TYPE, TEST_SEAT);
3707  
3708          expectWithMessage("Volume group volume after volume down in primary zone in primary group")
3709                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
3710                          TEST_PRIMARY_ZONE_GROUP_0)).isLessThan(volumeBefore);
3711      }
3712  
3713      @Test
onKeyEvent_forVolumeDownEvent_inPrimaryZone_forSecondaryGroup()3714      public void onKeyEvent_forVolumeDownEvent_inPrimaryZone_forSecondaryGroup() throws Exception {
3715          CarAudioService service = setUpAudioService();
3716          int volumeBefore = service.getGroupVolume(PRIMARY_AUDIO_ZONE,
3717                  TEST_PRIMARY_ZONE_GROUP_1);
3718          AudioPlaybackCallback callback = getCarAudioPlaybackCallback();
3719          callback.onPlaybackConfigChanged(List.of(new AudioPlaybackConfigurationBuilder()
3720                  .setUsage(USAGE_ASSISTANT)
3721                  .setDeviceAddress(VOICE_TEST_DEVICE)
3722                  .build())
3723          );
3724          KeyEventListener listener = getAudioKeyEventListener();
3725          when(mMockOccupantZoneService.getOccupantZoneIdForSeat(TEST_SEAT))
3726                  .thenReturn(PRIMARY_OCCUPANT_ZONE);
3727          when(mMockOccupantZoneService.getAudioZoneIdForOccupant(PRIMARY_OCCUPANT_ZONE))
3728                  .thenReturn(PRIMARY_AUDIO_ZONE);
3729          KeyEvent keyEvent = new KeyEvent(ACTION_DOWN, KEYCODE_VOLUME_DOWN);
3730  
3731          listener.onKeyEvent(keyEvent, TEST_DISPLAY_TYPE, TEST_SEAT);
3732  
3733          expectWithMessage("Assistant volume group volume after volume down")
3734                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
3735                          TEST_PRIMARY_ZONE_GROUP_1)).isLessThan(volumeBefore);
3736      }
3737  
3738      @Test
onKeyEvent_forVolumeDownEvent_inPrimaryZone_withHigherPriority()3739      public void onKeyEvent_forVolumeDownEvent_inPrimaryZone_withHigherPriority() throws Exception {
3740          CarAudioService service = setUpAudioService();
3741          int primaryGroupVolumeBefore = service.getGroupVolume(PRIMARY_AUDIO_ZONE,
3742                  TEST_PRIMARY_ZONE_GROUP_0);
3743          int voiceVolumeGroupBefore = service.getGroupVolume(PRIMARY_AUDIO_ZONE,
3744                  TEST_PRIMARY_ZONE_GROUP_2);
3745          AudioPlaybackCallback callback = getCarAudioPlaybackCallback();
3746          callback.onPlaybackConfigChanged(List.of(
3747                  new AudioPlaybackConfigurationBuilder()
3748                          .setUsage(USAGE_VOICE_COMMUNICATION)
3749                          .setDeviceAddress(CALL_TEST_DEVICE)
3750                          .build(),
3751                  new AudioPlaybackConfigurationBuilder()
3752                          .setUsage(USAGE_MEDIA)
3753                          .setDeviceAddress(MEDIA_TEST_DEVICE)
3754                          .build())
3755          );
3756          KeyEventListener listener = getAudioKeyEventListener();
3757          when(mMockOccupantZoneService.getOccupantZoneIdForSeat(TEST_SEAT))
3758                  .thenReturn(PRIMARY_OCCUPANT_ZONE);
3759          when(mMockOccupantZoneService.getAudioZoneIdForOccupant(PRIMARY_OCCUPANT_ZONE))
3760                  .thenReturn(PRIMARY_AUDIO_ZONE);
3761          KeyEvent keyEvent = new KeyEvent(ACTION_DOWN, KEYCODE_VOLUME_DOWN);
3762  
3763          listener.onKeyEvent(keyEvent, TEST_DISPLAY_TYPE, TEST_SEAT);
3764  
3765          expectWithMessage("Media volume group volume after volume down")
3766                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
3767                          TEST_PRIMARY_ZONE_GROUP_0)).isEqualTo(primaryGroupVolumeBefore);
3768          expectWithMessage("Call volume group volume after volume down")
3769                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
3770                          TEST_PRIMARY_ZONE_GROUP_2)).isLessThan(voiceVolumeGroupBefore);
3771      }
3772  
3773      @Test
onKeyEvent_forVolumeDownEvent_inPrimaryZone_withVersionTwoVolumeList()3774      public void onKeyEvent_forVolumeDownEvent_inPrimaryZone_withVersionTwoVolumeList()
3775              throws Exception {
3776          CarAudioService service = setUpCarAudioServiceWithVersionTwoVolumeList();
3777          int primaryGroupVolumeBefore = service.getGroupVolume(PRIMARY_AUDIO_ZONE,
3778                  TEST_PRIMARY_ZONE_GROUP_0);
3779          int voiceVolumeGroupBefore = service.getGroupVolume(PRIMARY_AUDIO_ZONE,
3780                  TEST_PRIMARY_ZONE_GROUP_2);
3781          AudioPlaybackCallback callback = getCarAudioPlaybackCallback();
3782          callback.onPlaybackConfigChanged(List.of(
3783                  new AudioPlaybackConfigurationBuilder()
3784                          .setUsage(USAGE_VOICE_COMMUNICATION)
3785                          .setDeviceAddress(CALL_TEST_DEVICE)
3786                          .build(),
3787                  new AudioPlaybackConfigurationBuilder()
3788                          .setUsage(USAGE_MEDIA)
3789                          .setDeviceAddress(MEDIA_TEST_DEVICE)
3790                          .build())
3791          );
3792          KeyEventListener listener = getAudioKeyEventListener();
3793          when(mMockOccupantZoneService.getOccupantZoneIdForSeat(TEST_SEAT))
3794                  .thenReturn(PRIMARY_OCCUPANT_ZONE);
3795          when(mMockOccupantZoneService.getAudioZoneIdForOccupant(PRIMARY_OCCUPANT_ZONE))
3796                  .thenReturn(PRIMARY_AUDIO_ZONE);
3797          KeyEvent keyEvent = new KeyEvent(ACTION_DOWN, KEYCODE_VOLUME_DOWN);
3798  
3799          listener.onKeyEvent(keyEvent, TEST_DISPLAY_TYPE, TEST_SEAT);
3800  
3801          expectWithMessage("Media volume group volume after volume down for volume list two")
3802                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
3803                          TEST_PRIMARY_ZONE_GROUP_0)).isEqualTo(primaryGroupVolumeBefore);
3804          expectWithMessage("Call volume group volume after volume down for volume list two")
3805                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
3806                          TEST_PRIMARY_ZONE_GROUP_2)).isLessThan(voiceVolumeGroupBefore);
3807      }
3808  
3809      @Test
onKeyEvent_forVolumeMuteEvent_inPrimaryZone()3810      public void onKeyEvent_forVolumeMuteEvent_inPrimaryZone() throws Exception {
3811          CarAudioService service = setUpAudioService();
3812          boolean muteBefore = service.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE,
3813                  TEST_PRIMARY_ZONE_GROUP_0);
3814          KeyEventListener listener = getAudioKeyEventListener();
3815          when(mMockOccupantZoneService.getOccupantZoneIdForSeat(TEST_SEAT))
3816                  .thenReturn(PRIMARY_OCCUPANT_ZONE);
3817          when(mMockOccupantZoneService.getAudioZoneIdForOccupant(PRIMARY_OCCUPANT_ZONE))
3818                  .thenReturn(PRIMARY_AUDIO_ZONE);
3819          KeyEvent keyEvent = new KeyEvent(ACTION_DOWN, KEYCODE_VOLUME_MUTE);
3820  
3821          listener.onKeyEvent(keyEvent, TEST_DISPLAY_TYPE, TEST_SEAT);
3822  
3823          expectWithMessage("Volume group volume after volume mute")
3824                  .that(service.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE,
3825                          TEST_PRIMARY_ZONE_GROUP_0)).isNotEqualTo(muteBefore);
3826      }
3827  
3828      @Test
onKeyEvent_forVolumeUpEvent_inSecondaryZone()3829      public void onKeyEvent_forVolumeUpEvent_inSecondaryZone() throws Exception {
3830          CarAudioService service = setUpAudioService();
3831          int volumeBefore = service.getGroupVolume(TEST_REAR_LEFT_ZONE_ID,
3832                  SECONDARY_ZONE_VOLUME_GROUP_ID);
3833          KeyEventListener listener = getAudioKeyEventListener();
3834          when(mMockOccupantZoneService.getOccupantZoneIdForSeat(TEST_SEAT))
3835                  .thenReturn(TEST_DRIVER_OCCUPANT_ZONE_ID);
3836          when(mMockOccupantZoneService.getAudioZoneIdForOccupant(TEST_DRIVER_OCCUPANT_ZONE_ID))
3837                  .thenReturn(TEST_REAR_LEFT_ZONE_ID);
3838          KeyEvent keyEvent = new KeyEvent(ACTION_DOWN, KEYCODE_VOLUME_UP);
3839  
3840          listener.onKeyEvent(keyEvent, TEST_DISPLAY_TYPE, TEST_SEAT);
3841  
3842          expectWithMessage("Secondary zone volume group after volume up")
3843                  .that(service.getGroupVolume(TEST_REAR_LEFT_ZONE_ID,
3844                          SECONDARY_ZONE_VOLUME_GROUP_ID))
3845                  .isGreaterThan(volumeBefore);
3846      }
3847  
3848      @Test
onKeyEvent_forVolumeDownEvent_inSecondaryZone()3849      public void onKeyEvent_forVolumeDownEvent_inSecondaryZone() throws Exception {
3850          CarAudioService service = setUpAudioService();
3851          int volumeBefore = service.getGroupVolume(TEST_REAR_LEFT_ZONE_ID,
3852                  SECONDARY_ZONE_VOLUME_GROUP_ID);
3853          KeyEventListener listener = getAudioKeyEventListener();
3854          when(mMockOccupantZoneService.getOccupantZoneIdForSeat(TEST_SEAT))
3855                  .thenReturn(TEST_DRIVER_OCCUPANT_ZONE_ID);
3856          when(mMockOccupantZoneService.getAudioZoneIdForOccupant(TEST_DRIVER_OCCUPANT_ZONE_ID))
3857                  .thenReturn(TEST_REAR_LEFT_ZONE_ID);
3858          KeyEvent keyEvent = new KeyEvent(ACTION_DOWN, KEYCODE_VOLUME_DOWN);
3859  
3860          listener.onKeyEvent(keyEvent, TEST_DISPLAY_TYPE, TEST_SEAT);
3861  
3862          expectWithMessage("Secondary zone volume group after volume down")
3863                  .that(service.getGroupVolume(TEST_REAR_LEFT_ZONE_ID,
3864                          SECONDARY_ZONE_VOLUME_GROUP_ID))
3865                  .isLessThan(volumeBefore);
3866      }
3867  
3868      @Test
onKeyEvent_forVolumeMuteEvent_inSecondaryZone()3869      public void onKeyEvent_forVolumeMuteEvent_inSecondaryZone() throws Exception {
3870          CarAudioService service = setUpAudioService();
3871          boolean muteBefore = service.isVolumeGroupMuted(TEST_REAR_LEFT_ZONE_ID,
3872                  SECONDARY_ZONE_VOLUME_GROUP_ID);
3873          KeyEventListener listener = getAudioKeyEventListener();
3874          when(mMockOccupantZoneService.getOccupantZoneIdForSeat(TEST_SEAT))
3875                  .thenReturn(TEST_DRIVER_OCCUPANT_ZONE_ID);
3876          when(mMockOccupantZoneService.getAudioZoneIdForOccupant(TEST_DRIVER_OCCUPANT_ZONE_ID))
3877                  .thenReturn(TEST_REAR_LEFT_ZONE_ID);
3878          KeyEvent keyEvent = new KeyEvent(ACTION_DOWN, KEYCODE_VOLUME_MUTE);
3879  
3880          listener.onKeyEvent(keyEvent, TEST_DISPLAY_TYPE, TEST_SEAT);
3881  
3882          expectWithMessage("Secondary zone volume group after volume mute")
3883                  .that(service.isVolumeGroupMuted(TEST_REAR_LEFT_ZONE_ID,
3884                          SECONDARY_ZONE_VOLUME_GROUP_ID))
3885                  .isNotEqualTo(muteBefore);
3886      }
3887  
3888      @Test
onAudioDeviceGainsChanged_forPrimaryZone_changesVolume()3889      public void onAudioDeviceGainsChanged_forPrimaryZone_changesVolume() throws Exception {
3890          CarAudioService service = setUpAudioService();
3891          HalAudioGainCallback callback = getHalAudioGainCallback();
3892          CarAudioGainConfigInfo carGain = createCarAudioGainConfigInfo(PRIMARY_AUDIO_ZONE,
3893                  MEDIA_TEST_DEVICE, TEST_GAIN_INDEX);
3894  
3895          callback.onAudioDeviceGainsChanged(List.of(Reasons.THERMAL_LIMITATION), List.of(carGain));
3896  
3897          expectWithMessage("New audio gains for primary zone")
3898                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
3899                          TEST_PRIMARY_ZONE_GROUP_0)).isEqualTo(TEST_GAIN_INDEX);
3900      }
3901  
3902      @Test
onAudioDeviceGainsChanged_forSecondaryZone_changesVolume()3903      public void onAudioDeviceGainsChanged_forSecondaryZone_changesVolume() throws Exception {
3904          CarAudioService service = setUpAudioService();
3905          HalAudioGainCallback callback = getHalAudioGainCallback();
3906          CarAudioGainConfigInfo carGain = createCarAudioGainConfigInfo(TEST_REAR_LEFT_ZONE_ID,
3907                  SECONDARY_TEST_DEVICE_CONFIG_0, TEST_GAIN_INDEX);
3908  
3909          callback.onAudioDeviceGainsChanged(List.of(Reasons.THERMAL_LIMITATION), List.of(carGain));
3910  
3911          expectWithMessage("New audio gains for secondary zone")
3912                  .that(service.getGroupVolume(TEST_REAR_LEFT_ZONE_ID,
3913                          TEST_PRIMARY_ZONE_GROUP_0)).isEqualTo(TEST_GAIN_INDEX);
3914      }
3915  
3916      @Test
onAudioDeviceGainsChanged_forIncorrectDeviceAddress_sameVolume()3917      public void onAudioDeviceGainsChanged_forIncorrectDeviceAddress_sameVolume() throws Exception {
3918          CarAudioService service = setUpAudioService();
3919          HalAudioGainCallback callback = getHalAudioGainCallback();
3920          int volumeBefore = service.getGroupVolume(PRIMARY_AUDIO_ZONE,
3921                  TEST_PRIMARY_ZONE_GROUP_0);
3922          CarAudioGainConfigInfo carGain = createCarAudioGainConfigInfo(PRIMARY_AUDIO_ZONE,
3923                  SECONDARY_TEST_DEVICE_CONFIG_0, TEST_GAIN_INDEX);
3924  
3925          callback.onAudioDeviceGainsChanged(List.of(Reasons.THERMAL_LIMITATION), List.of(carGain));
3926  
3927          expectWithMessage("Same audio gains for primary zone")
3928                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
3929                          TEST_PRIMARY_ZONE_GROUP_0)).isEqualTo(volumeBefore);
3930      }
3931  
3932      @Test
onAudioDeviceGainsChanged_forMultipleZones_changesVolume()3933      public void onAudioDeviceGainsChanged_forMultipleZones_changesVolume() throws Exception {
3934          CarAudioService service = setUpAudioService();
3935          HalAudioGainCallback callback = getHalAudioGainCallback();
3936          CarAudioGainConfigInfo primaryAudioZoneCarGain = createCarAudioGainConfigInfo(
3937                  PRIMARY_AUDIO_ZONE, MEDIA_TEST_DEVICE, TEST_GAIN_INDEX);
3938          CarAudioGainConfigInfo secondaryAudioZoneCarGain = createCarAudioGainConfigInfo(
3939                  TEST_REAR_LEFT_ZONE_ID, SECONDARY_TEST_DEVICE_CONFIG_0, TEST_GAIN_INDEX);
3940  
3941          callback.onAudioDeviceGainsChanged(List.of(Reasons.THERMAL_LIMITATION),
3942                  List.of(primaryAudioZoneCarGain, secondaryAudioZoneCarGain));
3943  
3944          expectWithMessage("New audio gains for primary zone")
3945                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE,
3946                          TEST_PRIMARY_ZONE_GROUP_0)).isEqualTo(TEST_GAIN_INDEX);
3947          expectWithMessage("New audio gains for secondary zone")
3948                  .that(service.getGroupVolume(TEST_REAR_LEFT_ZONE_ID,
3949                          TEST_PRIMARY_ZONE_GROUP_0)).isEqualTo(TEST_GAIN_INDEX);
3950      }
3951  
3952      @Test
onAudioDeviceGainsChanged_withMute_setsSystemMute()3953      public void onAudioDeviceGainsChanged_withMute_setsSystemMute() throws Exception {
3954          mSetFlagsRule.enableFlags(Flags.FLAG_CAR_AUDIO_MUTE_AMBIGUITY);
3955          CarAudioService service = setUpAudioService();
3956          HalAudioGainCallback halAudioGainCallback = getHalAudioGainCallback();
3957          CarAudioGainConfigInfo primaryAudioZoneCarGain = createCarAudioGainConfigInfo(
3958                  PRIMARY_AUDIO_ZONE, MEDIA_TEST_DEVICE, TEST_GAIN_INDEX);
3959  
3960          halAudioGainCallback.onAudioDeviceGainsChanged(List.of(Reasons.TCU_MUTE),
3961                  List.of(primaryAudioZoneCarGain));
3962  
3963          expectWithMessage("Hal mute status for primary zone %s", service
3964                  .getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0)).that(service
3965                  .getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0)
3966                  .isMutedBySystem()).isTrue();
3967      }
3968  
3969      @Test
onAudioPortsChanged_forMediaBus_changesVolumeRanges()3970      public void onAudioPortsChanged_forMediaBus_changesVolumeRanges() throws Exception {
3971          CarAudioService service = setUpAudioService();
3972          HalAudioModuleChangeCallback callback = getHalModuleChangeCallback();
3973          TestCarVolumeEventCallback volumeEventCallback =
3974                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
3975          service.registerCarVolumeEventCallback(volumeEventCallback);
3976          HalAudioDeviceInfo mediaBusDeviceInfo = createHalAudioDeviceInfo(
3977                  TEST_MEDIA_PORT_ID, TEST_MEDIA_PORT_NAME, TEST_GAIN_MIN_VALUE, TEST_GAIN_MAX_VALUE,
3978                  TEST_GAIN_DEFAULT_VALUE, TEST_GAIN_STEP_VALUE, OUT_DEVICE, MEDIA_TEST_DEVICE);
3979          CarVolumeGroupInfo volumeGroupInfoBefore =
3980                  service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0);
3981  
3982          callback.onAudioPortsChanged(List.of(mediaBusDeviceInfo));
3983  
3984          CarVolumeGroupInfo volumeGroupInfoAfter = service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE,
3985                  TEST_PRIMARY_ZONE_GROUP_0);
3986          expectWithMessage("update audio port for media device")
3987                  .that(volumeGroupInfoAfter).isNotEqualTo(volumeGroupInfoBefore);
3988          volumeEventCallback.waitForCallback();
3989          expectWithMessage("Volume events count after switching zone configuration")
3990                  .that(volumeEventCallback.getVolumeGroupEvents()).hasSize(1);
3991          CarVolumeGroupEvent groupEvent = volumeEventCallback.getVolumeGroupEvents().get(0);
3992          expectWithMessage("Volume group infos after switching zone configuration")
3993                  .that(groupEvent.getCarVolumeGroupInfos())
3994                  .containsExactly(volumeGroupInfoAfter);
3995      }
3996  
3997      @Test
onAudioPortsChanged_forNavBus_changesVolumeRanges()3998      public void onAudioPortsChanged_forNavBus_changesVolumeRanges() throws Exception {
3999          CarAudioService service = setUpAudioService();
4000          HalAudioModuleChangeCallback callback = getHalModuleChangeCallback();
4001          HalAudioDeviceInfo navBusDeviceInfo = createHalAudioDeviceInfo(
4002                  TEST_NAV_PORT_ID, TEST_NAV_PORT_NAME, TEST_GAIN_MIN_VALUE, TEST_GAIN_MAX_VALUE,
4003                  TEST_GAIN_DEFAULT_VALUE, TEST_GAIN_STEP_VALUE, OUT_DEVICE, NAVIGATION_TEST_DEVICE);
4004          CarVolumeGroupInfo volumeGroupInfoBefore =
4005                  service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_1);
4006  
4007          callback.onAudioPortsChanged(List.of(navBusDeviceInfo));
4008  
4009          expectWithMessage("update audio port for nav device")
4010                  .that(service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE,
4011                          TEST_PRIMARY_ZONE_GROUP_1)).isNotEqualTo(volumeGroupInfoBefore);
4012      }
4013  
4014      @Test
onAudioPortsChanged_forMultipleBuses_changesVolumeRanges()4015      public void onAudioPortsChanged_forMultipleBuses_changesVolumeRanges() throws Exception {
4016          CarAudioService service = setUpAudioService();
4017          HalAudioModuleChangeCallback callback = getHalModuleChangeCallback();
4018          HalAudioDeviceInfo mediaBusDeviceInfo = createHalAudioDeviceInfo(
4019                  TEST_MEDIA_PORT_ID, TEST_MEDIA_PORT_NAME, TEST_GAIN_MIN_VALUE, TEST_GAIN_MAX_VALUE,
4020                  TEST_GAIN_DEFAULT_VALUE, TEST_GAIN_STEP_VALUE, OUT_DEVICE, MEDIA_TEST_DEVICE);
4021          HalAudioDeviceInfo navBusDeviceInfo = createHalAudioDeviceInfo(
4022                  TEST_NAV_PORT_ID, TEST_NAV_PORT_NAME, TEST_GAIN_MIN_VALUE, TEST_GAIN_MAX_VALUE,
4023                  TEST_GAIN_DEFAULT_VALUE, TEST_GAIN_STEP_VALUE, OUT_DEVICE, NAVIGATION_TEST_DEVICE);
4024          CarVolumeGroupInfo mediaVolumeGroupInfoBefore =
4025                  service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0);
4026          CarVolumeGroupInfo navVolumeGroupInfoBefore =
4027                  service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_1);
4028  
4029          callback.onAudioPortsChanged(List.of(mediaBusDeviceInfo, navBusDeviceInfo));
4030  
4031          expectWithMessage("update audio port for media device")
4032                  .that(service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE,
4033                          TEST_PRIMARY_ZONE_GROUP_0)).isNotEqualTo(mediaVolumeGroupInfoBefore);
4034          expectWithMessage("update audio port for nav device")
4035                  .that(service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE,
4036                          TEST_PRIMARY_ZONE_GROUP_1)).isNotEqualTo(navVolumeGroupInfoBefore);
4037      }
4038  
4039      @Test
onAudioPortsChanged_withEmptyDeviceInfoList()4040      public void onAudioPortsChanged_withEmptyDeviceInfoList() throws Exception {
4041          CarAudioService service = setUpAudioService();
4042          HalAudioModuleChangeCallback callback = getHalModuleChangeCallback();
4043          TestCarVolumeEventCallback volumeEventCallback =
4044                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
4045          service.registerCarVolumeEventCallback(volumeEventCallback);
4046  
4047          callback.onAudioPortsChanged(Collections.EMPTY_LIST);
4048  
4049          expectWithMessage("No volume event callback invocation with empty device info list")
4050                  .that(volumeEventCallback.waitForCallback()).isFalse();
4051      }
4052  
4053      @Test
getActiveAudioAttributesForZone()4054      public void getActiveAudioAttributesForZone() throws Exception {
4055          CarAudioService service = setUpAudioService();
4056  
4057          expectWithMessage("Default active audio attributes").that(
4058                  service.getActiveAudioAttributesForZone(PRIMARY_AUDIO_ZONE)).isEmpty();
4059      }
4060  
4061      @Test
getActiveAudioAttributesForZone_withActiveHalFocus()4062      public void getActiveAudioAttributesForZone_withActiveHalFocus() throws Exception {
4063          when(mAudioManager.requestAudioFocus(any())).thenReturn(
4064                  AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
4065          CarAudioService service = setUpAudioService();
4066          requestHalAudioFocus(USAGE_ALARM);
4067  
4068          expectWithMessage("HAL active audio attributes")
4069                  .that(service.getActiveAudioAttributesForZone(PRIMARY_AUDIO_ZONE))
4070                  .containsExactly(new AudioAttributes.Builder().setUsage(USAGE_ALARM).build());
4071      }
4072  
4073      @Test
getActiveAudioAttributesForZone_withActivePlayback()4074      public void getActiveAudioAttributesForZone_withActivePlayback() throws Exception {
4075          CarAudioService service = setUpAudioService();
4076          mockActivePlayback();
4077  
4078          expectWithMessage("Playback active audio attributes")
4079                  .that(service.getActiveAudioAttributesForZone(PRIMARY_AUDIO_ZONE))
4080                  .containsExactly(new AudioAttributes.Builder().setUsage(USAGE_MEDIA).build());
4081      }
4082  
4083      @Test
getActiveAudioAttributesForZone_withActiveHalAndPlayback()4084      public void getActiveAudioAttributesForZone_withActiveHalAndPlayback() throws Exception {
4085          CarAudioService service = setUpAudioService();
4086          mockActivePlayback();
4087          when(mAudioManager.requestAudioFocus(any())).thenReturn(
4088                  AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
4089          requestHalAudioFocus(USAGE_VOICE_COMMUNICATION);
4090  
4091          expectWithMessage("Playback active audio attributes")
4092                  .that(service.getActiveAudioAttributesForZone(PRIMARY_AUDIO_ZONE))
4093                  .containsExactly(new AudioAttributes.Builder().setUsage(USAGE_MEDIA).build(),
4094                          new AudioAttributes.Builder().setUsage(USAGE_VOICE_COMMUNICATION).build());
4095      }
4096  
4097      @Test
getCallStateForZone_forPrimaryZone()4098      public void getCallStateForZone_forPrimaryZone() throws Exception {
4099          when(mMockTelephonyManagerWithoutSubscriptionId.getCallState())
4100                  .thenReturn(TelephonyManager.CALL_STATE_OFFHOOK);
4101          CarAudioService service = setUpAudioService();
4102          when(mMockOccupantZoneService.getDriverUserId()).thenReturn(TEST_DRIVER_USER_ID);
4103          when(mMockOccupantZoneService.getUserForOccupant(anyInt()))
4104                  .thenReturn(TEST_DRIVER_USER_ID, TEST_REAR_RIGHT_USER_ID);
4105          assignOccupantToAudioZones();
4106  
4107          expectWithMessage("Primary zone call state").that(
4108                  service.getCallStateForZone(PRIMARY_AUDIO_ZONE))
4109                  .isEqualTo(TelephonyManager.CALL_STATE_OFFHOOK);
4110      }
4111  
4112      @Test
getCallStateForZone_forNonPrimaryZone()4113      public void getCallStateForZone_forNonPrimaryZone() throws Exception {
4114          CarAudioService service = setUpAudioService();
4115          when(mMockTelephonyManagerWithoutSubscriptionId.getCallState())
4116                  .thenReturn(TelephonyManager.CALL_STATE_OFFHOOK);
4117          when(mMockOccupantZoneService.getDriverUserId()).thenReturn(TEST_DRIVER_USER_ID);
4118          when(mMockOccupantZoneService.getUserForOccupant(anyInt()))
4119                  .thenReturn(TEST_REAR_LEFT_USER_ID, TEST_REAR_RIGHT_USER_ID);
4120          assignOccupantToAudioZones();
4121  
4122          expectWithMessage("Secondary zone call state").that(
4123                          service.getCallStateForZone(TEST_REAR_LEFT_ZONE_ID))
4124                  .isEqualTo(TelephonyManager.CALL_STATE_IDLE);
4125      }
4126  
4127      @Test
getVolumeGroupAndContextCount()4128      public void getVolumeGroupAndContextCount() throws Exception {
4129          CarAudioService useCoreAudioCarAudioService =
4130                  setUpCarAudioServiceUsingCoreAudioRoutingAndVolume();
4131  
4132          verify(mAudioManager).registerVolumeGroupCallback(any(), any());
4133          expectWithMessage("Primary zone car volume group count")
4134                  .that(useCoreAudioCarAudioService.getVolumeGroupCount(PRIMARY_AUDIO_ZONE))
4135                  .isEqualTo(CoreAudioRoutingUtils.getVolumeGroups().size());
4136          expectWithMessage("Number of contexts")
4137                  .that(useCoreAudioCarAudioService.getCarAudioContext().getAllContextsIds().size())
4138                  .isEqualTo(CoreAudioRoutingUtils.getProductStrategies().size());
4139          expectWithMessage("Car Audio Contexts")
4140                  .that(useCoreAudioCarAudioService.getCarAudioContext().getAllContextsIds())
4141                  .containsExactly(CoreAudioRoutingUtils.NAV_STRATEGY_ID,
4142                          CoreAudioRoutingUtils.MUSIC_STRATEGY_ID,
4143                          CoreAudioRoutingUtils.OEM_STRATEGY_ID);
4144      }
4145  
4146      @Test
registerAudioZonesMirrorStatusCallback()4147      public void registerAudioZonesMirrorStatusCallback() throws Exception {
4148          CarAudioService service = setUpAudioService();
4149          TestAudioZonesMirrorStatusCallbackCallback callback =
4150                  new TestAudioZonesMirrorStatusCallbackCallback(/* count= */ 1);
4151  
4152          boolean registered = service.registerAudioZonesMirrorStatusCallback(callback);
4153  
4154          expectWithMessage("Audio zones mirror status callback registered status")
4155                  .that(registered).isTrue();
4156      }
4157  
4158      @Test
registerAudioZonesMirrorStatusCallback_withoutMirroringEnabled()4159      public void registerAudioZonesMirrorStatusCallback_withoutMirroringEnabled() throws Exception {
4160          CarAudioService service = setUpCarAudioServiceWithoutMirroring();
4161          TestAudioZonesMirrorStatusCallbackCallback callback =
4162                  new TestAudioZonesMirrorStatusCallbackCallback(/* count= */ 1);
4163  
4164          IllegalStateException thrown =
4165                  assertThrows(IllegalStateException.class, () ->
4166                          service.registerAudioZonesMirrorStatusCallback(callback));
4167  
4168          expectWithMessage("Disabled audio zones mirror register exception").that(thrown)
4169                  .hasMessageThat().contains("Audio zones mirroring is required");
4170      }
4171  
4172      @Test
registerAudioZonesMirrorStatusCallback_withNullCallback()4173      public void registerAudioZonesMirrorStatusCallback_withNullCallback() throws Exception {
4174          CarAudioService service = setUpAudioService();
4175  
4176          NullPointerException thrown =
4177                  assertThrows(NullPointerException.class, () ->
4178                      service.registerAudioZonesMirrorStatusCallback(/* callback= */ null));
4179  
4180          expectWithMessage("Null audio zones mirror register exception").that(thrown)
4181                  .hasMessageThat().contains("Audio zones mirror status callback");
4182      }
4183  
4184      @Test
unregisterAudioZonesMirrorStatusCallback_withNullCallback()4185      public void unregisterAudioZonesMirrorStatusCallback_withNullCallback() throws Exception {
4186          CarAudioService service = setUpAudioService();
4187  
4188          NullPointerException thrown =
4189                  assertThrows(NullPointerException.class, () -> service
4190                          .unregisterAudioZonesMirrorStatusCallback(/* callback= */ null));
4191  
4192          expectWithMessage("Null audio zones mirror unregister exception").that(thrown)
4193                  .hasMessageThat().contains("Audio zones mirror status callback");
4194      }
4195  
4196      @Test
enableMirrorForAudioZones_withNullAudioZones()4197      public void enableMirrorForAudioZones_withNullAudioZones() throws Exception {
4198          CarAudioService service = setUpAudioService();
4199  
4200          NullPointerException thrown =
4201                  assertThrows(NullPointerException.class, () ->
4202                          service.enableMirrorForAudioZones(/* audioZones= */ null));
4203  
4204          expectWithMessage("Null mirror audio zones exception").that(thrown)
4205                  .hasMessageThat().contains("Mirror audio zones");
4206      }
4207  
4208      @Test
enableMirrorForAudioZones()4209      public void enableMirrorForAudioZones() throws Exception {
4210          CarAudioService service = setUpAudioService();
4211          TestAudioZonesMirrorStatusCallbackCallback callback =
4212                  getAudioZonesMirrorStatusCallback(service);
4213          assignOccupantToAudioZones();
4214  
4215          service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
4216  
4217          callback.waitForCallback();
4218          expectWithMessage("Audio mirror approved status").that(callback.getLastStatus())
4219                  .isEqualTo(CarAudioManager.AUDIO_REQUEST_STATUS_APPROVED);
4220          expectWithMessage("Audio mirror approved zones").that(callback.getLastZoneIds())
4221                  .asList().containsExactly(TEST_REAR_LEFT_ZONE_ID, TEST_REAR_RIGHT_ZONE_ID);
4222      }
4223  
4224      @Test
enableMirrorForAudioZones_sendsMirrorInfoToAudioHAL()4225      public void enableMirrorForAudioZones_sendsMirrorInfoToAudioHAL() throws Exception {
4226          CarAudioService service = setUpAudioService();
4227          TestAudioZonesMirrorStatusCallbackCallback callback =
4228                  getAudioZonesMirrorStatusCallback(service);
4229          assignOccupantToAudioZones();
4230  
4231          service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
4232  
4233          callback.waitForCallback();
4234          String audioMirrorInfoCommand = captureAudioMirrorInfoCommand(1);
4235          List<String> commands = Arrays.asList(audioMirrorInfoCommand.split(";"));
4236          String sourceDeviceAddress = removeUpToEquals(commands.get(0));
4237          expectWithMessage("Audio mirror source info").that(sourceDeviceAddress)
4238                  .isEqualTo(MIRROR_TEST_DEVICE);
4239          String destinationsDevices = commands.get(1);
4240          List<String> deviceAddresses = Arrays.asList(removeUpToEquals(destinationsDevices)
4241                  .split(","));
4242          expectWithMessage("Audio mirror zone one info").that(deviceAddresses.get(0))
4243                  .isEqualTo(SECONDARY_TEST_DEVICE_CONFIG_0);
4244          expectWithMessage("Audio mirror zone two info").that(deviceAddresses.get(1))
4245                  .isEqualTo(TERTIARY_TEST_DEVICE_1);
4246      }
4247  
4248      @Test
enableMirrorForAudioZones_forPrimaryZone_fails()4249      public void enableMirrorForAudioZones_forPrimaryZone_fails() throws Exception {
4250          CarAudioService service = setUpAudioService();
4251          assignOccupantToAudioZones();
4252          int[] audioZones = new int[]{TEST_REAR_LEFT_ZONE_ID, PRIMARY_AUDIO_ZONE};
4253  
4254          IllegalArgumentException thrown =
4255                  assertThrows(IllegalArgumentException.class, () ->
4256                          service.enableMirrorForAudioZones(audioZones));
4257  
4258          expectWithMessage("Mirror audio zones with primary zone exception").that(thrown)
4259                  .hasMessageThat().contains("not allowed for primary audio zone");
4260      }
4261  
4262      @Test
enableMirrorForAudioZones_forNonAssignedZone_fails()4263      public void enableMirrorForAudioZones_forNonAssignedZone_fails() throws Exception {
4264          when(mMockOccupantZoneService.getUserForOccupant(TEST_REAR_RIGHT_OCCUPANT_ZONE_ID))
4265                  .thenReturn(UserManagerHelper.USER_NULL);
4266          CarAudioService service = setUpAudioService();
4267          getAudioZonesMirrorStatusCallback(service);
4268          assignOccupantToAudioZones();
4269  
4270          IllegalStateException thrown =
4271                  assertThrows(IllegalStateException.class, () ->
4272                          service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES));
4273  
4274          expectWithMessage("Mirror audio zones for unoccupied audio zone exception")
4275                  .that(thrown).hasMessageThat().contains("must have an active user");
4276      }
4277  
4278      @Test
enableMirrorForAudioZones_forRepeatingZones_fails()4279      public void enableMirrorForAudioZones_forRepeatingZones_fails() throws Exception {
4280          CarAudioService service = setUpAudioService();
4281          assignOccupantToAudioZones();
4282          int[] audioZones = new int[]{TEST_REAR_LEFT_ZONE_ID,
4283                  TEST_REAR_LEFT_ZONE_ID};
4284  
4285          IllegalArgumentException thrown =
4286                  assertThrows(IllegalArgumentException.class, () ->
4287                          service.enableMirrorForAudioZones(audioZones));
4288  
4289          expectWithMessage("Repeated mirror audio zones exception").that(thrown)
4290                  .hasMessageThat().contains("must be unique");
4291      }
4292  
4293      @Test
enableMirrorForAudioZones_forAlreadyMirroredZones()4294      public void enableMirrorForAudioZones_forAlreadyMirroredZones() throws Exception {
4295          CarAudioService service = setUpAudioService();
4296          TestAudioZonesMirrorStatusCallbackCallback callback =
4297                  getAudioZonesMirrorStatusCallback(service);
4298          assignOccupantToAudioZones();
4299          service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
4300          callback.waitForCallback();
4301          callback.reset(/* count= */ 1);
4302  
4303          IllegalStateException thrown =
4304                  assertThrows(IllegalStateException.class, () ->
4305                          service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES));
4306  
4307          expectWithMessage("Audio mirror exception for repeating request")
4308                  .that(thrown).hasMessageThat().contains("is already mirroring");
4309  
4310      }
4311  
4312      @Test
enableMirrorForAudioZones_afterSharedInPrimaryZone()4313      public void enableMirrorForAudioZones_afterSharedInPrimaryZone() throws Exception {
4314          CarAudioService service = setUpAudioService();
4315          TestPrimaryZoneMediaAudioRequestCallback
4316                  requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
4317          service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
4318          TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
4319          assignOccupantToAudioZones();
4320          long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
4321                  TEST_REAR_RIGHT_PASSENGER_OCCUPANT);
4322          requestToken.waitForCallback();
4323          requestToken.reset();
4324          service.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allow= */ true);
4325          requestToken.waitForCallback();
4326          requestToken.reset();
4327  
4328          IllegalStateException thrown =
4329                  assertThrows(IllegalStateException.class, () ->
4330                          service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES));
4331  
4332          expectWithMessage("Mirror audio zones while sharing in primary zone exception")
4333                  .that(thrown).hasMessageThat().contains("currently sharing to primary zone");
4334      }
4335  
4336      @Test
enableMirrorForAudioZones_forInvertedMirrorConfiguration()4337      public void enableMirrorForAudioZones_forInvertedMirrorConfiguration() throws Exception {
4338          CarAudioService service = setUpAudioService();
4339          TestAudioZonesMirrorStatusCallbackCallback callback =
4340                  getAudioZonesMirrorStatusCallback(service);
4341          assignOccupantToAudioZones();
4342          service.enableMirrorForAudioZones(new int[] {TEST_REAR_RIGHT_ZONE_ID,
4343                  TEST_REAR_LEFT_ZONE_ID});
4344          callback.waitForCallback();
4345          callback.reset(/* count= */ 1);
4346  
4347          IllegalStateException thrown =
4348                  assertThrows(IllegalStateException.class, () ->
4349                          service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES));
4350  
4351          expectWithMessage("Audio mirror exception for inverted zone request")
4352                  .that(thrown).hasMessageThat().contains("is already mirroring");
4353      }
4354  
4355      @Test
enableMirrorForAudioZones_withNoMoreMirrorDevices_fails()4356      public void enableMirrorForAudioZones_withNoMoreMirrorDevices_fails() throws Exception {
4357          CarAudioService service = setUpAudioService();
4358          TestAudioZonesMirrorStatusCallbackCallback callback =
4359                  getAudioZonesMirrorStatusCallback(service);
4360          assignOccupantToAudioZones();
4361          service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
4362          callback.waitForCallback();
4363          callback.reset(/* count= */ 1);
4364  
4365          IllegalStateException thrown = assertThrows(IllegalStateException.class, () ->
4366                  service.enableMirrorForAudioZones(
4367                          new int[] {TEST_FRONT_ZONE_ID, TEST_REAR_ROW_3_ZONE_ID}));
4368  
4369          expectWithMessage("Audio mirror for out of mirror devices exception")
4370                  .that(thrown).hasMessageThat().contains("available mirror output devices");
4371      }
4372  
4373      @Test
canEnableAudioMirror_withOutOfMirroringDevices()4374      public void canEnableAudioMirror_withOutOfMirroringDevices() throws Exception {
4375          CarAudioService service = setUpAudioService();
4376          TestAudioZonesMirrorStatusCallbackCallback callback =
4377                  getAudioZonesMirrorStatusCallback(service);
4378          assignOccupantToAudioZones();
4379          service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
4380          callback.waitForCallback();
4381  
4382          expectWithMessage("Can audio mirror status").that(service
4383                          .canEnableAudioMirror())
4384                  .isEqualTo(AUDIO_MIRROR_OUT_OF_OUTPUT_DEVICES);
4385      }
4386  
4387      @Test
canEnableAudioMirror_withAudioMirrorEnabledAndNoPendingRequests()4388      public void canEnableAudioMirror_withAudioMirrorEnabledAndNoPendingRequests() throws Exception {
4389          CarAudioService service = setUpAudioService();
4390  
4391          expectWithMessage("Can audio mirror status before audio mirror request")
4392                  .that(service.canEnableAudioMirror())
4393                  .isEqualTo(AUDIO_MIRROR_CAN_ENABLE);
4394      }
4395  
4396      @Test
canEnableAudioMirror_withMirroringDisabled()4397      public void canEnableAudioMirror_withMirroringDisabled() throws Exception {
4398          CarAudioService service = setUpCarAudioServiceWithoutMirroring();
4399  
4400          IllegalStateException thrown = assertThrows(IllegalStateException.class, () ->
4401                          service.canEnableAudioMirror());
4402  
4403          expectWithMessage("Can enable audio mirror exception")
4404                  .that(thrown).hasMessageThat().contains("Audio zones mirroring is required");
4405      }
4406  
4407      @Test
extendAudioMirrorRequest()4408      public void extendAudioMirrorRequest() throws Exception {
4409          CarAudioService service = setUpAudioService();
4410          TestAudioZonesMirrorStatusCallbackCallback callback =
4411                  getAudioZonesMirrorStatusCallback(service);
4412          assignOccupantToAudioZones();
4413          long requestId = service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
4414          callback.waitForCallback();
4415          callback.reset(1);
4416  
4417          service.extendAudioMirrorRequest(requestId, new int[] {TEST_FRONT_ZONE_ID});
4418  
4419          callback.waitForCallback();
4420          expectWithMessage("Audio mirror approved status").that(callback.getLastStatus())
4421                  .isEqualTo(CarAudioManager.AUDIO_REQUEST_STATUS_APPROVED);
4422          expectWithMessage("Audio mirror approved zones").that(callback.getLastZoneIds())
4423                  .asList().containsExactly(TEST_REAR_LEFT_ZONE_ID, TEST_REAR_RIGHT_ZONE_ID,
4424                          TEST_FRONT_ZONE_ID);
4425      }
4426  
4427      @Test
extendAudioMirrorRequest_withNullAudioZones()4428      public void extendAudioMirrorRequest_withNullAudioZones() throws Exception {
4429          CarAudioService service = setUpAudioService();
4430          TestAudioZonesMirrorStatusCallbackCallback callback =
4431                  getAudioZonesMirrorStatusCallback(service);
4432          assignOccupantToAudioZones();
4433          long requestId = service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
4434          callback.waitForCallback();
4435          callback.reset(1);
4436  
4437          NullPointerException thrown =
4438                  assertThrows(NullPointerException.class, () ->
4439                          service.extendAudioMirrorRequest(requestId,
4440                                  /* audioZones = */ null));
4441  
4442          expectWithMessage("Null audio zones to extend for mirror request exception")
4443                  .that(thrown).hasMessageThat().contains("Mirror audio zones");
4444      }
4445  
4446      @Test
extendAudioMirrorRequest_withPrimaryAudioZone()4447      public void extendAudioMirrorRequest_withPrimaryAudioZone() throws Exception {
4448          CarAudioService service = setUpAudioService();
4449          TestAudioZonesMirrorStatusCallbackCallback callback =
4450                  getAudioZonesMirrorStatusCallback(service);
4451          assignOccupantToAudioZones();
4452          long requestId = service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
4453          callback.waitForCallback();
4454          callback.reset(1);
4455  
4456          IllegalArgumentException thrown =
4457                  assertThrows(IllegalArgumentException.class, () ->
4458                          service.extendAudioMirrorRequest(requestId,
4459                                  new int[] {PRIMARY_AUDIO_ZONE}));
4460  
4461          expectWithMessage("Primary audio zone to extend for mirror request exception")
4462                  .that(thrown).hasMessageThat().contains(
4463                          "Audio mirroring not allowed for primary audio zone");
4464      }
4465  
4466      @Test
getAudioZoneConfigInfos()4467      public void getAudioZoneConfigInfos() throws Exception {
4468          CarAudioService service = setUpAudioService();
4469  
4470          List<CarAudioZoneConfigInfo> zoneConfigInfos =
4471                  service.getAudioZoneConfigInfos(TEST_REAR_LEFT_ZONE_ID);
4472  
4473          List<String> zoneConfigNames = zoneConfigInfos.stream().map(cf -> cf.getName()).toList();
4474          expectWithMessage("Zone configurations for secondary zone").that(zoneConfigNames)
4475                  .containsExactly(SECONDARY_ZONE_CONFIG_NAME_1, SECONDARY_ZONE_CONFIG_NAME_2);
4476      }
4477  
4478      @Test
getCurrentAudioZoneConfigInfo()4479      public void getCurrentAudioZoneConfigInfo() throws Exception {
4480          CarAudioService service = setUpAudioService();
4481  
4482          CarAudioZoneConfigInfo currentZoneConfigInfo =
4483                  service.getCurrentAudioZoneConfigInfo(TEST_REAR_LEFT_ZONE_ID);
4484  
4485          expectWithMessage("Name of current zone configuration for secondary zone")
4486                  .that(currentZoneConfigInfo.getName()).isEqualTo(SECONDARY_ZONE_CONFIG_NAME_1);
4487      }
4488  
4489      @Test
switchZoneToConfig()4490      public void switchZoneToConfig() throws Exception {
4491          CarAudioService service = setUpAudioService();
4492          SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl();
4493          assignOccupantToAudioZones();
4494          CarAudioZoneConfigInfo zoneConfigSwitchTo = getZoneConfigToSwitch(service,
4495                  TEST_REAR_LEFT_ZONE_ID);
4496  
4497          service.switchZoneToConfig(zoneConfigSwitchTo, callback);
4498  
4499          callback.waitForCallback();
4500          expectWithMessage("Updated zone configuration")
4501                  .that(callback.getZoneConfig())
4502                  .isEqualTo(getUpdatedCarAudioZoneConfigInfo(zoneConfigSwitchTo, service));
4503          expectWithMessage("Zone configuration switching status")
4504                  .that(callback.getSwitchStatus()).isTrue();
4505      }
4506  
4507      @Test
switchZoneToConfig_forNonAssignedZone_fails()4508      public void switchZoneToConfig_forNonAssignedZone_fails() throws Exception {
4509          when(mMockOccupantZoneService.getUserForOccupant(TEST_REAR_LEFT_OCCUPANT_ZONE_ID))
4510                  .thenReturn(UserManagerHelper.USER_NULL);
4511          CarAudioService service = setUpAudioService();
4512          SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl();
4513          assignOccupantToAudioZones();
4514          CarAudioZoneConfigInfo  zoneConfigSwitchTo = getZoneConfigToSwitch(service,
4515                  TEST_REAR_LEFT_ZONE_ID);
4516  
4517          IllegalStateException thrown =
4518                  assertThrows(IllegalStateException.class, () ->
4519                          service.switchZoneToConfig(zoneConfigSwitchTo, callback));
4520  
4521          expectWithMessage("Switching zone configuration for unoccupied audio zone exception")
4522                  .that(thrown).hasMessageThat().contains("must have an active user");
4523      }
4524  
4525      @Test
switchZoneToConfig_afterSharedInPrimaryZone_fails()4526      public void switchZoneToConfig_afterSharedInPrimaryZone_fails() throws Exception {
4527          CarAudioService service = setUpAudioService();
4528          SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl();
4529          TestPrimaryZoneMediaAudioRequestCallback
4530                  requestToken = new TestPrimaryZoneMediaAudioRequestCallback();
4531          service.registerPrimaryZoneMediaAudioRequestCallback(requestToken);
4532          TestMediaRequestStatusCallback requestCallback = new TestMediaRequestStatusCallback();
4533          assignOccupantToAudioZones();
4534          long requestId = service.requestMediaAudioOnPrimaryZone(requestCallback,
4535                  TEST_REAR_LEFT_PASSENGER_OCCUPANT);
4536          requestToken.waitForCallback();
4537          requestToken.reset();
4538          service.allowMediaAudioOnPrimaryZone(requestToken, requestId, /* allow= */ true);
4539          requestToken.waitForCallback();
4540          requestToken.reset();
4541          CarAudioZoneConfigInfo zoneConfigSwitchTo = getZoneConfigToSwitch(service,
4542                  TEST_REAR_LEFT_ZONE_ID);
4543  
4544          IllegalStateException thrown =
4545                  assertThrows(IllegalStateException.class, () ->
4546                          service.switchZoneToConfig(zoneConfigSwitchTo, callback));
4547  
4548          expectWithMessage("Switching zone configuration while sharing in primary zone exception")
4549                  .that(thrown).hasMessageThat().contains("currently sharing to primary zone");
4550      }
4551  
4552      @Test
switchZoneToConfig_afterMirroring_fails()4553      public void switchZoneToConfig_afterMirroring_fails() throws Exception {
4554          CarAudioService service = setUpAudioService();
4555          SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl();
4556          TestAudioZonesMirrorStatusCallbackCallback mirrorCallback =
4557                  getAudioZonesMirrorStatusCallback(service);
4558          assignOccupantToAudioZones();
4559          service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
4560          mirrorCallback.waitForCallback();
4561          mirrorCallback.reset(/* count= */ 1);
4562          CarAudioZoneConfigInfo zoneConfigSwitchTo = getZoneConfigToSwitch(service,
4563                  TEST_REAR_LEFT_ZONE_ID);
4564  
4565          IllegalStateException thrown =
4566                  assertThrows(IllegalStateException.class, () ->
4567                          service.switchZoneToConfig(zoneConfigSwitchTo, callback));
4568  
4569          expectWithMessage("Switching zone configuration while audio mirroring").that(thrown)
4570                  .hasMessageThat().contains("currently in a mirroring configuration");
4571      }
4572  
4573      @Test
switchZoneToConfig_withPendingFocus_regainsFocus()4574      public void switchZoneToConfig_withPendingFocus_regainsFocus() throws Exception {
4575          CarAudioService service = setUpAudioService();
4576          SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl();
4577          assignOccupantToAudioZones();
4578          AudioFocusInfo audioFocusInfo = createAudioFocusInfoForMedia(TEST_REAR_RIGHT_UID);
4579          service.requestAudioFocusForTest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
4580          CarAudioZoneConfigInfo zoneConfigSwitchTo = getZoneConfigToSwitch(service,
4581                  TEST_REAR_RIGHT_ZONE_ID);
4582  
4583          service.switchZoneToConfig(zoneConfigSwitchTo, callback);
4584  
4585          callback.waitForCallback();
4586          expectWithMessage("Updated zone configuration with pending focus")
4587                  .that(callback.getZoneConfig())
4588                  .isEqualTo(getUpdatedCarAudioZoneConfigInfo(zoneConfigSwitchTo, service));
4589          expectWithMessage("Zone configuration switching status with pending focus")
4590                  .that(callback.getSwitchStatus()).isTrue();
4591          List<Integer> focusChanges = getFocusChanges(audioFocusInfo);
4592          expectWithMessage("Media audio focus changes after switching zone")
4593                  .that(focusChanges).containsExactly(AUDIOFOCUS_LOSS_TRANSIENT, AUDIOFOCUS_GAIN);
4594      }
4595  
4596      @Test
switchZoneToConfig_withPendingFocus_updatesDuckingInfo()4597      public void switchZoneToConfig_withPendingFocus_updatesDuckingInfo() throws Exception {
4598          CarAudioService service = setUpAudioService();
4599          SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl();
4600          assignOccupantToAudioZones();
4601          AudioFocusInfo audioFocusInfo = createAudioFocusInfoForMedia(TEST_REAR_RIGHT_UID);
4602          service.requestAudioFocusForTest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
4603          ArgumentCaptor<List<CarDuckingInfo>> carDuckingInfosCaptor =
4604                  ArgumentCaptor.forClass(List.class);
4605          verify(mAudioControlWrapperAidl).onDevicesToDuckChange(carDuckingInfosCaptor.capture());
4606          verifyMediaDuckingInfoInZone(carDuckingInfosCaptor, TEST_REAR_RIGHT_ZONE_ID,
4607                  " before switching zone");
4608          CarAudioZoneConfigInfo zoneConfigSwitchTo = getZoneConfigToSwitch(service,
4609                  TEST_REAR_RIGHT_ZONE_ID);
4610  
4611          service.switchZoneToConfig(zoneConfigSwitchTo, callback);
4612  
4613          callback.waitForCallback();
4614          expectWithMessage("Updated zone configuration with pending focus")
4615                  .that(callback.getZoneConfig())
4616                  .isEqualTo(getUpdatedCarAudioZoneConfigInfo(zoneConfigSwitchTo, service));
4617          expectWithMessage("Zone configuration switching status with pending focus")
4618                  .that(callback.getSwitchStatus()).isTrue();
4619          verify(mAudioControlWrapperAidl, times(2))
4620                  .onDevicesToDuckChange(carDuckingInfosCaptor.capture());
4621          verifyMediaDuckingInfoInZone(carDuckingInfosCaptor, TEST_REAR_RIGHT_ZONE_ID,
4622                  " after switching zone");
4623      }
4624  
4625      @Test
switchZoneToConfig_withCurrentZoneConfigAndPendingFocus_notLoseAndRegainFocus()4626      public void switchZoneToConfig_withCurrentZoneConfigAndPendingFocus_notLoseAndRegainFocus()
4627              throws Exception {
4628          CarAudioService service = setUpAudioService();
4629          SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl();
4630          assignOccupantToAudioZones();
4631          AudioFocusInfo audioFocusInfo = createAudioFocusInfoForMedia(TEST_REAR_RIGHT_UID);
4632          service.requestAudioFocusForTest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
4633          CarAudioZoneConfigInfo currentZoneConfig =
4634                  service.getCurrentAudioZoneConfigInfo(TEST_REAR_RIGHT_ZONE_ID);
4635  
4636          service.switchZoneToConfig(currentZoneConfig, callback);
4637  
4638          callback.waitForCallback();
4639          expectWithMessage("Updated zone configuration with current configuration")
4640                  .that(callback.getZoneConfig()).isEqualTo(currentZoneConfig);
4641          expectWithMessage("Zone configuration switching status with current configuration")
4642                  .that(callback.getSwitchStatus()).isTrue();
4643          verify(mAudioManager, never()).dispatchAudioFocusChange(eq(audioFocusInfo), anyInt(),
4644                  any(AudioPolicy.class));
4645      }
4646  
4647      @Test
switchZoneToConfig_withVolumeGroupEventCallbackRegistered_invokesEvent()4648      public void switchZoneToConfig_withVolumeGroupEventCallbackRegistered_invokesEvent()
4649              throws Exception {
4650          CarAudioService service = setUpAudioService();
4651          SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl();
4652          TestCarVolumeEventCallback volumeEventCallback =
4653                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
4654          assignOccupantToAudioZones();
4655          CarAudioZoneConfigInfo zoneConfigSwitchTo = getZoneConfigToSwitch(service,
4656                  TEST_REAR_LEFT_ZONE_ID);
4657          service.registerCarVolumeEventCallback(volumeEventCallback);
4658  
4659          service.switchZoneToConfig(zoneConfigSwitchTo, callback);
4660  
4661          callback.waitForCallback();
4662          expectWithMessage("Updated zone configuration")
4663                  .that(callback.getZoneConfig())
4664                  .isEqualTo(getUpdatedCarAudioZoneConfigInfo(zoneConfigSwitchTo, service));
4665          expectWithMessage("Zone configuration switching status")
4666                  .that(callback.getSwitchStatus()).isTrue();
4667          volumeEventCallback.waitForCallback();
4668          expectWithMessage("Volume events count after switching zone configuration")
4669                  .that(volumeEventCallback.getVolumeGroupEvents()).hasSize(1);
4670          CarVolumeGroupEvent groupEvent = volumeEventCallback.getVolumeGroupEvents().get(0);
4671          expectWithMessage("Volume event type after switching zone configuration")
4672                  .that(groupEvent.getEventTypes())
4673                  .isEqualTo(CarVolumeGroupEvent.EVENT_TYPE_ZONE_CONFIGURATION_CHANGED);
4674          expectWithMessage("Volume group infos after switching zone configuration")
4675                  .that(groupEvent.getCarVolumeGroupInfos())
4676                  .containsExactly(mTestSecondaryZoneConfig1VolumeInfo0,
4677                          mTestSecondaryZoneConfig1VolumeInfo1);
4678      }
4679  
4680      @Test
switchZoneToConfig_updatesVolumeGroupInfos()4681      public void switchZoneToConfig_updatesVolumeGroupInfos()
4682              throws Exception {
4683          CarAudioService service = setUpAudioService();
4684          SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl();
4685          assignOccupantToAudioZones();
4686          Log.e(TAG, "Current volume group " + service.getVolumeGroupInfosForZone(
4687                  TEST_REAR_LEFT_ZONE_ID));
4688          expectWithMessage("Volume group infos before switching zone configuration")
4689                  .that(service.getVolumeGroupInfosForZone(TEST_REAR_LEFT_ZONE_ID))
4690                  .containsExactly(mTestSecondaryConfig0VolumeGroup0Info);
4691          CarAudioZoneConfigInfo zoneConfigSwitchTo = getZoneConfigToSwitch(service,
4692                  TEST_REAR_LEFT_ZONE_ID);
4693  
4694          service.switchZoneToConfig(zoneConfigSwitchTo, callback);
4695  
4696          callback.waitForCallback();
4697          expectWithMessage("Volume group infos after switching zone configuration")
4698                  .that(service.getVolumeGroupInfosForZone(TEST_REAR_LEFT_ZONE_ID))
4699                  .containsExactly(mTestSecondaryZoneConfig1VolumeInfo0,
4700                          mTestSecondaryZoneConfig1VolumeInfo1);
4701      }
4702  
4703      @Test
switchZoneToConfig_withDynamicDevicesFlagEnabled()4704      public void switchZoneToConfig_withDynamicDevicesFlagEnabled() throws Exception {
4705          mSetFlagsRule.enableFlags(Flags.FLAG_CAR_AUDIO_DYNAMIC_DEVICES);
4706          CarAudioService service = setUpAudioService();
4707          SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl();
4708          assignOccupantToAudioZones();
4709          CarAudioZoneConfigInfo previousConfig = service
4710                  .getCurrentAudioZoneConfigInfo(TEST_REAR_LEFT_ZONE_ID);
4711          CarAudioZoneConfigInfo zoneConfigSwitchTo =
4712                  getZoneConfigToSwitch(service, TEST_REAR_LEFT_ZONE_ID);
4713  
4714          service.switchZoneToConfig(zoneConfigSwitchTo, callback);
4715  
4716          callback.waitForCallback();
4717          expectWithMessage("Updated zone configuration, with dynamic devices enabled")
4718                  .that(callback.getZoneConfig().hasSameConfigInfo(zoneConfigSwitchTo)).isTrue();
4719          expectWithMessage("Zone configuration switched status, with dynamic devices enabled")
4720                  .that(callback.getSwitchStatus()).isTrue();
4721          CarAudioZoneConfigInfo switchedInfo = service
4722                  .getCurrentAudioZoneConfigInfo(TEST_REAR_LEFT_ZONE_ID);
4723          expectWithMessage("Switched config active status")
4724                  .that(switchedInfo.isActive()).isTrue();
4725          expectWithMessage("Switched config selected status")
4726                  .that(switchedInfo.isSelected()).isTrue();
4727          CarAudioZoneConfigInfo previousUpdated =
4728                  getUpdatedCarAudioZoneConfigInfo(previousConfig, service);
4729          expectWithMessage("Previous config active status")
4730                  .that(previousUpdated.isActive()).isTrue();
4731          expectWithMessage("Previous config selected status")
4732                  .that(previousUpdated.isSelected()).isFalse();
4733      }
4734  
4735      @Test
switchZoneToConfig_toDynamicConfig_withDynamicDevicesInMultipleZones()4736      public void switchZoneToConfig_toDynamicConfig_withDynamicDevicesInMultipleZones()
4737              throws Exception {
4738          setUpTempFileForAudioConfiguration(R.raw.car_audio_configuration_using_dynamic_devices);
4739          setUpTempFileForAudioFadeConfiguration(R.raw.car_audio_fade_configuration);
4740          CarAudioService dynamicDeviceService =
4741                  setUpAudioServiceWithDynamicDevices(mTempCarAudioConfigFile,
4742                          mTempCarAudioFadeConfigFile);
4743          dynamicDeviceService.init();
4744          assignOccupantToAudioZones();
4745          SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl();
4746          TestAudioZoneConfigurationsChangeCallback configCallback =
4747                  getRegisteredZoneConfigCallback(dynamicDeviceService);
4748          AudioDeviceCallback deviceCallback = captureAudioDeviceCallback();
4749          deviceCallback.onAudioDevicesAdded(new AudioDeviceInfo[]{mBTAudioDeviceInfo});
4750          configCallback.waitForCallback();
4751          configCallback.reset();
4752          List<CarAudioZoneConfigInfo> zoneConfigInfos =
4753                  dynamicDeviceService.getAudioZoneConfigInfos(PRIMARY_AUDIO_ZONE);
4754          CarAudioZoneConfigInfo zoneConfigSwitchTo = zoneConfigInfos.stream()
4755                  .filter(c -> c.getName().equals(PRIMARY_CONFIG_NAME_DYNAMIC_DEVICES))
4756                  .findFirst().orElseThrow();
4757  
4758          dynamicDeviceService.switchZoneToConfig(zoneConfigSwitchTo, callback);
4759  
4760          configCallback.waitForCallback();
4761          callback.waitForCallback();
4762          CarAudioZoneConfigInfo secondaryZoneBTConfig = configCallback.mInfos.stream()
4763                  .filter(c -> c.getName().equals(SECONDARY_ZONE_BT_CONFIG_NAME))
4764                  .findFirst().orElseThrow();
4765          expectWithMessage("Inactive dynamic config due to dynamic device being used")
4766                  .that(secondaryZoneBTConfig.isActive()).isFalse();
4767      }
4768  
4769      @Test
switchZoneToConfig_backFromDynamicConfig_withDynamicDevicesInMultipleZones()4770      public void switchZoneToConfig_backFromDynamicConfig_withDynamicDevicesInMultipleZones()
4771              throws Exception {
4772          setUpTempFileForAudioConfiguration(R.raw.car_audio_configuration_using_dynamic_devices);
4773          setUpTempFileForAudioFadeConfiguration(R.raw.car_audio_fade_configuration);
4774          CarAudioService dynamicDeviceService =
4775                  setUpAudioServiceWithDynamicDevices(mTempCarAudioConfigFile,
4776                          mTempCarAudioFadeConfigFile);
4777          dynamicDeviceService.init();
4778          assignOccupantToAudioZones();
4779          SwitchAudioZoneConfigCallbackImpl callback = new SwitchAudioZoneConfigCallbackImpl();
4780          TestAudioZoneConfigurationsChangeCallback configCallback =
4781                  getRegisteredZoneConfigCallback(dynamicDeviceService);
4782          AudioDeviceCallback deviceCallback = captureAudioDeviceCallback();
4783          deviceCallback.onAudioDevicesAdded(new AudioDeviceInfo[]{mBTAudioDeviceInfo});
4784          configCallback.waitForCallback();
4785          configCallback.reset();
4786          List<CarAudioZoneConfigInfo> zoneConfigInfos =
4787                  dynamicDeviceService.getAudioZoneConfigInfos(PRIMARY_AUDIO_ZONE);
4788          CarAudioZoneConfigInfo dynamicConfig = zoneConfigInfos.stream()
4789                  .filter(c -> c.getName().equals(PRIMARY_CONFIG_NAME_DYNAMIC_DEVICES))
4790                  .findFirst().orElseThrow();
4791          dynamicDeviceService.switchZoneToConfig(dynamicConfig, callback);
4792          callback.waitForCallback();
4793          callback.reset();
4794          configCallback.waitForCallback();
4795          configCallback.reset();
4796          CarAudioZoneConfigInfo defaultConfig = zoneConfigInfos.stream()
4797                  .filter(CarAudioZoneConfigInfo::isDefault).findFirst().orElseThrow();
4798  
4799          dynamicDeviceService.switchZoneToConfig(defaultConfig, callback);
4800  
4801          configCallback.waitForCallback();
4802          callback.waitForCallback();
4803          CarAudioZoneConfigInfo secondaryZoneBTConfig = configCallback.mInfos.stream()
4804                  .filter(c -> c.getName().equals(SECONDARY_ZONE_BT_CONFIG_NAME))
4805                  .findFirst().orElseThrow();
4806          expectWithMessage("Re-activated dynamic config due to dynamic device not used")
4807                  .that(secondaryZoneBTConfig.isActive()).isTrue();
4808      }
4809  
4810      @Test
registerAudioZoneConfigsChangeCallback()4811      public void registerAudioZoneConfigsChangeCallback() throws Exception {
4812          IAudioZoneConfigurationsChangeCallback callback =
4813                  new TestAudioZoneConfigurationsChangeCallback();
4814          CarAudioService service = setUpAudioService();
4815  
4816          boolean registered = service.registerAudioZoneConfigsChangeCallback(callback);
4817  
4818          expectWithMessage("Car audio zone configuration change register status")
4819                  .that(registered).isTrue();
4820      }
4821  
4822      @Test
registerAudioZoneConfigsChangeCallback_multipleTimes()4823      public void registerAudioZoneConfigsChangeCallback_multipleTimes() throws Exception {
4824          IAudioZoneConfigurationsChangeCallback callback =
4825                  new TestAudioZoneConfigurationsChangeCallback();
4826          CarAudioService service = setUpAudioService();
4827          service.registerAudioZoneConfigsChangeCallback(callback);
4828  
4829          boolean registered = service.registerAudioZoneConfigsChangeCallback(callback);
4830  
4831          expectWithMessage("Car audio zone configuration change re-register status")
4832                  .that(registered).isTrue();
4833      }
4834  
4835      @Test
registerAudioZoneConfigsChangeCallback_withNullCallback()4836      public void registerAudioZoneConfigsChangeCallback_withNullCallback() throws Exception {
4837          CarAudioService service = setUpAudioService();
4838  
4839          NullPointerException thrown = assertThrows(NullPointerException.class,
4840                  () -> service.registerAudioZoneConfigsChangeCallback(null));
4841  
4842          expectWithMessage("Car audio zone configuration change registration exception")
4843                  .that(thrown).hasMessageThat().contains("Car audio zone configs");
4844      }
4845  
4846      @Test
onAudioDevicesAdded_forDynamicDevicesEnabled()4847      public void onAudioDevicesAdded_forDynamicDevicesEnabled() throws Exception {
4848          CarAudioService audioServiceWithDynamicDevices = setUpAudioServiceWithDynamicDevices();
4849          audioServiceWithDynamicDevices.init();
4850          TestAudioZoneConfigurationsChangeCallback
4851                  configCallback = getRegisteredZoneConfigCallback(audioServiceWithDynamicDevices);
4852          AudioDeviceCallback deviceCallback = captureAudioDeviceCallback();
4853  
4854          deviceCallback.onAudioDevicesAdded(new AudioDeviceInfo[]{mBTAudioDeviceInfo});
4855  
4856          configCallback.waitForCallback();
4857          List<CarAudioZoneConfigInfo> zoneConfigInfos =
4858                  audioServiceWithDynamicDevices.getAudioZoneConfigInfos(PRIMARY_AUDIO_ZONE);
4859          CarAudioZoneConfigInfo btConfig = zoneConfigInfos.stream()
4860                  .filter(config -> config.getName().equals(PRIMARY_CONFIG_NAME_DYNAMIC_DEVICES))
4861                  .findFirst().orElseThrow();
4862          expectWithMessage("Enabled bluetooth configuration").that(btConfig.isActive()).isTrue();
4863      }
4864  
4865      @Test
onAudioDevicesAdded_forDynamicDevicesEnabled_triggersCallback()4866      public void onAudioDevicesAdded_forDynamicDevicesEnabled_triggersCallback() throws Exception {
4867          CarAudioService serviceWithDynamicDevices = setUpAudioServiceWithDynamicDevices();
4868          serviceWithDynamicDevices.init();
4869          TestAudioZoneConfigurationsChangeCallback
4870                  configCallback = getRegisteredZoneConfigCallback(serviceWithDynamicDevices);
4871          AudioDeviceCallback deviceCallback = captureAudioDeviceCallback();
4872  
4873          deviceCallback.onAudioDevicesAdded(new AudioDeviceInfo[]{mBTAudioDeviceInfo});
4874  
4875          configCallback.waitForCallback();
4876          expectWithMessage("Enabled dynamic config callback status").that(configCallback.mStatus)
4877                  .isEqualTo(CONFIG_STATUS_CHANGED);
4878          CarAudioZoneConfigInfo btConfig = configCallback.mInfos.stream()
4879                  .filter(config -> config.getName().equals(PRIMARY_CONFIG_NAME_DYNAMIC_DEVICES))
4880                  .findFirst().orElseThrow();
4881          expectWithMessage("Callback enabled bluetooth configuration").that(btConfig.isActive())
4882                  .isTrue();
4883      }
4884  
4885      @Test
onAudioDevicesAdded_forDynamicDevicesEnabled_withAudioServerDown()4886      public void onAudioDevicesAdded_forDynamicDevicesEnabled_withAudioServerDown()
4887              throws Exception {
4888          CarAudioService audioServiceWithDynamicDevices = setUpAudioServiceWithDynamicDevices();
4889          audioServiceWithDynamicDevices.init();
4890          TestAudioZoneConfigurationsChangeCallback
4891                  configCallback = getRegisteredZoneConfigCallback(audioServiceWithDynamicDevices);
4892          AudioDeviceCallback deviceCallback = captureAudioDeviceCallback();
4893          audioServiceWithDynamicDevices.releaseAudioCallbacks(/* isAudioServerDown= */ true);
4894  
4895          deviceCallback.onAudioDevicesAdded(new AudioDeviceInfo[]{mBTAudioDeviceInfo});
4896  
4897          configCallback.waitForCallback();
4898          List<CarAudioZoneConfigInfo> zoneConfigInfos =
4899                  audioServiceWithDynamicDevices.getAudioZoneConfigInfos(PRIMARY_AUDIO_ZONE);
4900          CarAudioZoneConfigInfo btConfig = zoneConfigInfos.stream()
4901                  .filter(config -> config.getName().equals(PRIMARY_CONFIG_NAME_DYNAMIC_DEVICES))
4902                  .findFirst().orElseThrow();
4903          expectWithMessage("Disabled bluetooth configuration with audio server down")
4904                  .that(btConfig.isActive()).isFalse();
4905      }
4906  
4907      @Test
onAudioDevicesRemoved_forDynamicDevicesEnabled_triggersCallback()4908      public void onAudioDevicesRemoved_forDynamicDevicesEnabled_triggersCallback()
4909              throws Exception {
4910          CarAudioService serviceWithDynamicDevices = setUpAudioServiceWithDynamicDevices();
4911          serviceWithDynamicDevices.init();
4912          AudioDeviceCallback deviceCallback = captureAudioDeviceCallback();
4913          TestAudioZoneConfigurationsChangeCallback
4914                  configCallback = getRegisteredZoneConfigCallback(serviceWithDynamicDevices);
4915          deviceCallback.onAudioDevicesAdded(new AudioDeviceInfo[]{mBTAudioDeviceInfo});
4916          configCallback.waitForCallback();
4917          configCallback.reset();
4918  
4919          deviceCallback.onAudioDevicesRemoved(new AudioDeviceInfo[]{mBTAudioDeviceInfo});
4920  
4921          configCallback.waitForCallback();
4922          expectWithMessage("Disabled dynamic config callback status").that(configCallback.mStatus)
4923                  .isEqualTo(CONFIG_STATUS_CHANGED);
4924          CarAudioZoneConfigInfo btConfig = configCallback.mInfos.stream()
4925                  .filter(config -> config.getName().equals(PRIMARY_CONFIG_NAME_DYNAMIC_DEVICES))
4926                  .findFirst().orElseThrow();
4927          expectWithMessage("Callback disabled bluetooth configuration").that(btConfig.isActive())
4928                  .isFalse();
4929      }
4930  
4931      @Test
onAudioDevicesRemoved_afterAdded_forDynamicDevicesEnabled()4932      public void onAudioDevicesRemoved_afterAdded_forDynamicDevicesEnabled() throws Exception {
4933          CarAudioService audioServiceWithDynamicDevices = setUpAudioServiceWithDynamicDevices();
4934          audioServiceWithDynamicDevices.init();
4935          TestAudioZoneConfigurationsChangeCallback
4936                  configCallback = getRegisteredZoneConfigCallback(audioServiceWithDynamicDevices);
4937          AudioDeviceCallback deviceCallback = captureAudioDeviceCallback();
4938          deviceCallback.onAudioDevicesAdded(new AudioDeviceInfo[]{mBTAudioDeviceInfo});
4939          configCallback.waitForCallback();
4940          configCallback.reset();
4941  
4942          deviceCallback.onAudioDevicesRemoved(new AudioDeviceInfo[]{mBTAudioDeviceInfo});
4943  
4944          configCallback.waitForCallback();
4945          List<CarAudioZoneConfigInfo> zoneConfigInfos =
4946                  audioServiceWithDynamicDevices.getAudioZoneConfigInfos(PRIMARY_AUDIO_ZONE);
4947          CarAudioZoneConfigInfo btConfig = zoneConfigInfos.stream()
4948                  .filter(config -> config.getName().equals(PRIMARY_CONFIG_NAME_DYNAMIC_DEVICES))
4949                  .findFirst().orElseThrow();
4950          expectWithMessage("Enabled bluetooth configuration after removed device")
4951                  .that(btConfig.isActive()).isFalse();
4952      }
4953  
4954      @Test
onAudioDevicesRemoved_forSelectedDynamicDevicesEnabled_triggersCallback()4955      public void onAudioDevicesRemoved_forSelectedDynamicDevicesEnabled_triggersCallback()
4956              throws Exception {
4957          SwitchAudioZoneConfigCallbackImpl switchCallback = new SwitchAudioZoneConfigCallbackImpl();
4958          CarAudioService serviceWithDynamicDevices = setUpAudioServiceWithDynamicDevices();
4959          serviceWithDynamicDevices.init();
4960          assignOccupantToAudioZones();
4961          AudioDeviceCallback deviceCallback = captureAudioDeviceCallback();
4962          TestAudioZoneConfigurationsChangeCallback
4963                  configCallback = getRegisteredZoneConfigCallback(serviceWithDynamicDevices);
4964          deviceCallback.onAudioDevicesAdded(new AudioDeviceInfo[]{mBTAudioDeviceInfo});
4965          configCallback.waitForCallback();
4966          configCallback.reset();
4967          List<CarAudioZoneConfigInfo> infos =
4968                  serviceWithDynamicDevices.getAudioZoneConfigInfos(PRIMARY_AUDIO_ZONE);
4969          CarAudioZoneConfigInfo btConfig = infos.stream().filter(
4970                  config -> config.getName().equals(PRIMARY_CONFIG_NAME_DYNAMIC_DEVICES))
4971                  .findFirst().orElseThrow();
4972          serviceWithDynamicDevices.switchZoneToConfig(btConfig, switchCallback);
4973          switchCallback.waitForCallback();
4974  
4975          deviceCallback.onAudioDevicesRemoved(new AudioDeviceInfo[]{mBTAudioDeviceInfo});
4976  
4977          configCallback.waitForCallback();
4978          CarAudioZoneConfigInfo updatedBTConfig = configCallback.mInfos.stream().filter(
4979                          config -> config.getName().equals(PRIMARY_CONFIG_NAME_DYNAMIC_DEVICES))
4980                  .findFirst().orElseThrow();
4981          expectWithMessage("Disabled selected dynamic config callback status")
4982                  .that(configCallback.mStatus).isEqualTo(CONFIG_STATUS_AUTO_SWITCHED);
4983          expectWithMessage("Callback disabled selected bluetooth configuration")
4984                  .that(updatedBTConfig.isActive()).isFalse();
4985      }
4986  
4987      @Test
onAudioDevicesRemoved_forDynamicDevicesEnabled_afterAddedWithAudioServerDown()4988      public void onAudioDevicesRemoved_forDynamicDevicesEnabled_afterAddedWithAudioServerDown()
4989              throws Exception {
4990          CarAudioService audioServiceWithDynamicDevices = setUpAudioServiceWithDynamicDevices();
4991          audioServiceWithDynamicDevices.init();
4992          TestAudioZoneConfigurationsChangeCallback
4993                  configCallback = getRegisteredZoneConfigCallback(audioServiceWithDynamicDevices);
4994          AudioDeviceCallback deviceCallback = captureAudioDeviceCallback();
4995          deviceCallback.onAudioDevicesAdded(new AudioDeviceInfo[]{mBTAudioDeviceInfo});
4996          configCallback.waitForCallback();
4997          configCallback.reset();
4998          audioServiceWithDynamicDevices.releaseAudioCallbacks(/* isAudioServerDown= */ true);
4999  
5000          deviceCallback.onAudioDevicesRemoved(new AudioDeviceInfo[]{mBTAudioDeviceInfo});
5001  
5002          configCallback.waitForCallback();
5003          List<CarAudioZoneConfigInfo> zoneConfigInfos =
5004                  audioServiceWithDynamicDevices.getAudioZoneConfigInfos(PRIMARY_AUDIO_ZONE);
5005          CarAudioZoneConfigInfo btConfig = zoneConfigInfos.stream()
5006                  .filter(config -> config.getName().equals(PRIMARY_CONFIG_NAME_DYNAMIC_DEVICES))
5007                  .findFirst().orElseThrow();
5008          expectWithMessage(
5009                  "Enabled bluetooth configuration after removed device with audio server down")
5010                  .that(btConfig.isActive()).isTrue();
5011      }
5012  
5013      @Test
unregisterAudioZoneConfigsChangeCallback()5014      public void unregisterAudioZoneConfigsChangeCallback() throws Exception {
5015          IAudioZoneConfigurationsChangeCallback callback =
5016                  new TestAudioZoneConfigurationsChangeCallback();
5017          CarAudioService service = setUpAudioService();
5018          service.registerAudioZoneConfigsChangeCallback(callback);
5019  
5020          boolean registered = service.unregisterAudioZoneConfigsChangeCallback(callback);
5021  
5022          expectWithMessage("Car audio zone configuration change un-register status")
5023                  .that(registered).isTrue();
5024      }
5025  
5026      @Test
unregisterAudioZoneConfigsChangeCallback_afterUnregister_fails()5027      public void unregisterAudioZoneConfigsChangeCallback_afterUnregister_fails() throws Exception {
5028          IAudioZoneConfigurationsChangeCallback callback =
5029                  new TestAudioZoneConfigurationsChangeCallback();
5030          CarAudioService service = setUpAudioService();
5031          service.registerAudioZoneConfigsChangeCallback(callback);
5032          service.unregisterAudioZoneConfigsChangeCallback(callback);
5033  
5034          boolean registered = service.unregisterAudioZoneConfigsChangeCallback(callback);
5035  
5036          expectWithMessage("Car audio zone configuration change un-register multiple times status")
5037                  .that(registered).isFalse();
5038      }
5039  
5040      @Test
unregisterAudioZoneConfigsChangeCallback_withNullCallback()5041      public void unregisterAudioZoneConfigsChangeCallback_withNullCallback() throws Exception {
5042          CarAudioService service = setUpAudioService();
5043  
5044          NullPointerException thrown = assertThrows(NullPointerException.class,
5045                  () -> service.unregisterAudioZoneConfigsChangeCallback(null));
5046  
5047          expectWithMessage("Car audio zone configuration change un-registration exception")
5048                  .that(thrown).hasMessageThat().contains("Car audio zone configs");
5049      }
5050  
5051      @Test
disableAudioMirrorForZone_withInvalidZone()5052      public void disableAudioMirrorForZone_withInvalidZone() throws Exception {
5053          CarAudioService service = setUpAudioService();
5054          assignOccupantToAudioZones();
5055  
5056          IllegalArgumentException thrown =
5057                  assertThrows(IllegalArgumentException.class, () ->
5058                          service.disableAudioMirrorForZone(INVALID_AUDIO_ZONE));
5059  
5060          expectWithMessage("Disable mirror for invalid audio zone exception").that(thrown)
5061                          .hasMessageThat().contains("Invalid audio zone");
5062      }
5063  
5064      @Test
disableAudioMirrorForZone_withMirroringDisabled()5065      public void disableAudioMirrorForZone_withMirroringDisabled() throws Exception {
5066          CarAudioService service = setUpCarAudioServiceWithoutMirroring();
5067  
5068          IllegalStateException thrown =
5069                  assertThrows(IllegalStateException.class, () ->
5070                          service.disableAudioMirrorForZone(TEST_REAR_LEFT_ZONE_ID));
5071  
5072          expectWithMessage("Disable mirror for zone with audio mirroring disabled")
5073                  .that(thrown).hasMessageThat().contains("Audio zones mirroring is required");
5074      }
5075  
5076      @Test
disableAudioMirrorForZone_forNonMirroringZone()5077      public void disableAudioMirrorForZone_forNonMirroringZone() throws Exception {
5078          CarAudioService service = setUpAudioService();
5079          TestAudioZonesMirrorStatusCallbackCallback callback =
5080                  getAudioZonesMirrorStatusCallback(service);
5081          assignOccupantToAudioZones();
5082  
5083          service.disableAudioMirrorForZone(TEST_REAR_LEFT_ZONE_ID);
5084  
5085          callback.waitForCallback();
5086          expectWithMessage("Disable audio mirror for non-mirroring zone callback count")
5087                  .that(callback.mNumberOfCalls).isEqualTo(0);
5088      }
5089  
5090      @Test
disableAudioMirrorForZone_forMirroringZones()5091      public void disableAudioMirrorForZone_forMirroringZones() throws Exception {
5092          CarAudioService service = setUpAudioService();
5093          TestAudioZonesMirrorStatusCallbackCallback callback =
5094                  getAudioZonesMirrorStatusCallback(service);
5095          assignOccupantToAudioZones();
5096          service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
5097          callback.waitForCallback();
5098          callback.reset(/* count= */ 1);
5099  
5100          service.disableAudioMirrorForZone(TEST_REAR_LEFT_ZONE_ID);
5101  
5102          callback.waitForCallback();
5103          expectWithMessage("Callback count for disable audio mirror")
5104                  .that(callback.mNumberOfCalls).isEqualTo(2);
5105          expectWithMessage("Callback status disable audio mirror for mirroring zone")
5106                  .that(callback.getLastStatus())
5107                  .isEqualTo(CarAudioManager.AUDIO_REQUEST_STATUS_STOPPED);
5108          expectWithMessage("Callback zones disable audio mirror for mirroring zone")
5109                  .that(callback.getLastZoneIds()).asList()
5110                  .containsExactly(TEST_REAR_RIGHT_ZONE_ID, TEST_REAR_LEFT_ZONE_ID);
5111      }
5112  
5113      @Test
disableAudioMirrorForZone_forMirroringZones_forFirstMirroringConfig()5114      public void disableAudioMirrorForZone_forMirroringZones_forFirstMirroringConfig()
5115              throws Exception {
5116          CarAudioService service = setUpAudioService();
5117          TestAudioZonesMirrorStatusCallbackCallback callback =
5118                  getAudioZonesMirrorStatusCallback(service);
5119          assignOccupantToAudioZones();
5120          service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
5121          callback.waitForCallback();
5122          callback.reset(/* count= */ 1);
5123  
5124          service.disableAudioMirrorForZone(TEST_REAR_RIGHT_ZONE_ID);
5125  
5126          callback.waitForCallback();
5127          expectWithMessage("Callback count for disable audio mirror")
5128                  .that(callback.mNumberOfCalls).isEqualTo(2);
5129          expectWithMessage("Callback status disable audio mirror for mirroring zone")
5130                  .that(callback.getLastStatus())
5131                  .isEqualTo(CarAudioManager.AUDIO_REQUEST_STATUS_STOPPED);
5132          expectWithMessage("Callback zones disable audio mirror for mirroring zone")
5133                  .that(callback.getLastZoneIds()).asList()
5134                  .containsExactly(TEST_REAR_RIGHT_ZONE_ID, TEST_REAR_LEFT_ZONE_ID);
5135          String audioMirrorOffCommand = captureAudioMirrorInfoCommand(2);
5136          expectWithMessage("Audio HAL off source for mirroring zone")
5137                  .that(audioMirrorOffCommand).contains(MIRROR_TEST_DEVICE);
5138          expectWithMessage("Audio HAL off signal for mirroring zone")
5139                  .that(audioMirrorOffCommand).contains(MIRROR_OFF_SIGNAL);
5140      }
5141  
5142      @Test
disableAudioMirrorForZone_withPendingFocus()5143      public void disableAudioMirrorForZone_withPendingFocus()
5144              throws Exception {
5145          CarAudioService service = setUpAudioService();
5146          TestAudioZonesMirrorStatusCallbackCallback callback =
5147                  getAudioZonesMirrorStatusCallback(service);
5148          assignOccupantToAudioZones();
5149          service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
5150          callback.waitForCallback();
5151          callback.reset(/* count= */ 2);
5152          AudioFocusInfo audioFocusInfo = createAudioFocusInfoForMedia(TEST_REAR_RIGHT_UID);
5153          service.requestAudioFocusForTest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
5154  
5155          service.disableAudioMirrorForZone(TEST_REAR_LEFT_ZONE_ID);
5156  
5157          callback.waitForCallback();
5158          List<Integer> focusChanges = getFocusChanges(audioFocusInfo);
5159          expectWithMessage("Media audio focus changes after disable mirror for zone")
5160                  .that(focusChanges).containsExactly(AUDIOFOCUS_LOSS_TRANSIENT, AUDIOFOCUS_GAIN);
5161      }
5162  
5163      @Test
disableAudioMirror_withoutMirroringDisabled()5164      public void disableAudioMirror_withoutMirroringDisabled() throws Exception {
5165          CarAudioService service = setUpCarAudioServiceWithoutMirroring();
5166  
5167          IllegalStateException thrown =
5168                  assertThrows(IllegalStateException.class, () ->
5169                          service.disableAudioMirror(INVALID_REQUEST_ID));
5170  
5171          expectWithMessage("Disable mirror for audio zones with audio mirroring disabled")
5172                  .that(thrown).hasMessageThat().contains("Audio zones mirroring is required");
5173      }
5174  
5175      @Test
disableAudioMirror_withInvalidRequestId()5176      public void disableAudioMirror_withInvalidRequestId() throws Exception {
5177          CarAudioService service = setUpAudioService();
5178  
5179          IllegalArgumentException thrown =
5180                  assertThrows(IllegalArgumentException.class, () ->
5181                          service.disableAudioMirror(INVALID_REQUEST_ID));
5182  
5183          expectWithMessage("Disable mirror for audio zones with audio invalid request id")
5184                  .that(thrown).hasMessageThat().contains("INVALID_REQUEST_ID");
5185      }
5186  
5187      @Test
disableAudioMirror_forNonMirroringZone()5188      public void disableAudioMirror_forNonMirroringZone() throws Exception {
5189          CarAudioService service = setUpAudioService();
5190          TestAudioZonesMirrorStatusCallbackCallback callback =
5191                  getAudioZonesMirrorStatusCallback(service);
5192          assignOccupantToAudioZones();
5193          long requestId = service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
5194          callback.waitForCallback();
5195          callback.reset(1);
5196          service.disableAudioMirror(requestId);
5197          callback.waitForCallback();
5198          callback.reset(1);
5199  
5200          service.disableAudioMirror(requestId);
5201  
5202          expectWithMessage("Disable audio mirror for non-mirroring zone callback count")
5203                  .that(callback.mNumberOfCalls).isEqualTo(2);
5204      }
5205  
5206      @Test
disableAudioMirror_forMirroringZones()5207      public void disableAudioMirror_forMirroringZones() throws Exception {
5208          CarAudioService service = setUpAudioService();
5209          TestAudioZonesMirrorStatusCallbackCallback callback =
5210                  getAudioZonesMirrorStatusCallback(service);
5211          assignOccupantToAudioZones();
5212          long requestId = service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
5213          callback.waitForCallback();
5214          callback.reset(/* count= */ 1);
5215  
5216          service.disableAudioMirror(requestId);
5217  
5218          callback.waitForCallback();
5219          expectWithMessage("Callback count for disable mirror in audio zones")
5220                  .that(callback.mNumberOfCalls).isEqualTo(2);
5221          expectWithMessage("Callback status disable audio mirror for mirroring zones")
5222                  .that(callback.getLastStatus())
5223                  .isEqualTo(CarAudioManager.AUDIO_REQUEST_STATUS_STOPPED);
5224          expectWithMessage("Callback zones disable audio mirror for mirroring zones")
5225                  .that(callback.getLastZoneIds()).asList()
5226                  .containsExactly(TEST_REAR_RIGHT_ZONE_ID, TEST_REAR_LEFT_ZONE_ID);
5227          String audioMirrorOffCommand = captureAudioMirrorInfoCommand(2);
5228          expectWithMessage("Audio HAL off source for mirroring zones")
5229                  .that(audioMirrorOffCommand).contains(MIRROR_TEST_DEVICE);
5230          expectWithMessage("Audio HAL off signal for mirroring zones")
5231                  .that(audioMirrorOffCommand).contains(MIRROR_OFF_SIGNAL);
5232      }
5233  
5234      @Test
disableAudioMirror_withPendingFocus()5235      public void disableAudioMirror_withPendingFocus() throws Exception {
5236          CarAudioService service = setUpAudioService();
5237          TestAudioZonesMirrorStatusCallbackCallback callback =
5238                  getAudioZonesMirrorStatusCallback(service);
5239          assignOccupantToAudioZones();
5240          long requestId = service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
5241          callback.waitForCallback();
5242          callback.reset(/* count= */ 2);
5243          AudioFocusInfo audioFocusInfo = createAudioFocusInfoForMedia(TEST_REAR_RIGHT_UID);
5244          service.requestAudioFocusForTest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
5245  
5246          service.disableAudioMirror(requestId);
5247  
5248          callback.waitForCallback();
5249          List<Integer> focusChanges = getFocusChanges(audioFocusInfo);
5250          expectWithMessage("Media audio focus changes after disable audio"
5251                  + "mirror for zones config").that(focusChanges)
5252                  .containsExactly(AUDIOFOCUS_LOSS_TRANSIENT, AUDIOFOCUS_GAIN);
5253      }
5254  
5255      @Test
getMirrorAudioZonesForAudioZone_withoutMirroringEnabled()5256      public void getMirrorAudioZonesForAudioZone_withoutMirroringEnabled()
5257              throws Exception {
5258          CarAudioService service = setUpAudioService();
5259          assignOccupantToAudioZones();
5260  
5261          int[] zones = service.getMirrorAudioZonesForAudioZone(TEST_REAR_RIGHT_ZONE_ID);
5262  
5263          expectWithMessage("Mirroring zones for non mirror zone %s", TEST_REAR_RIGHT_ZONE_ID)
5264                  .that(zones).asList().isEmpty();
5265      }
5266  
5267      @Test
getMirrorAudioZonesForAudioZone_withMirroringEnabled()5268      public void getMirrorAudioZonesForAudioZone_withMirroringEnabled() throws Exception {
5269          CarAudioService service = setUpAudioService();
5270          TestAudioZonesMirrorStatusCallbackCallback callback =
5271                  getAudioZonesMirrorStatusCallback(service);
5272          assignOccupantToAudioZones();
5273          service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
5274          callback.waitForCallback();
5275  
5276          int[] zones = service.getMirrorAudioZonesForAudioZone(TEST_REAR_RIGHT_ZONE_ID);
5277  
5278          expectWithMessage("Mirroring zones for mirror zone %s", TEST_REAR_RIGHT_ZONE_ID).that(zones)
5279                  .asList().containsExactly(TEST_REAR_LEFT_ZONE_ID, TEST_REAR_RIGHT_ZONE_ID);
5280      }
5281  
5282      @Test
getMirrorAudioZonesForAudioZone_afterDisableMirror()5283      public void getMirrorAudioZonesForAudioZone_afterDisableMirror() throws Exception {
5284          CarAudioService service = setUpAudioService();
5285          TestAudioZonesMirrorStatusCallbackCallback callback =
5286                  getAudioZonesMirrorStatusCallback(service);
5287          assignOccupantToAudioZones();
5288          long requestId = service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
5289          callback.waitForCallback();
5290          callback.reset(1);
5291          service.disableAudioMirror(requestId);
5292          callback.waitForCallback();
5293  
5294          int[] zones = service.getMirrorAudioZonesForAudioZone(TEST_REAR_RIGHT_ZONE_ID);
5295  
5296          expectWithMessage("Mirroring zones for mirror zone %s after disabling mirroring",
5297                  TEST_REAR_RIGHT_ZONE_ID).that(zones).asList().isEmpty();
5298      }
5299  
5300      @Test
getMirrorAudioZonesForAudioZone_afterPassengerLogout()5301      public void getMirrorAudioZonesForAudioZone_afterPassengerLogout() throws Exception {
5302          CarAudioService service = setUpAudioService();
5303          TestAudioZonesMirrorStatusCallbackCallback callback =
5304                  getAudioZonesMirrorStatusCallback(service);
5305          assignOccupantToAudioZones();
5306          service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
5307          callback.waitForCallback();
5308          callback.reset(1);
5309          simulateLogoutRightPassengers();
5310          callback.waitForCallback();
5311  
5312          int[] zones = service.getMirrorAudioZonesForAudioZone(TEST_REAR_RIGHT_ZONE_ID);
5313  
5314          expectWithMessage("Mirroring zones for mirror zone %s after logout",
5315                  TEST_REAR_RIGHT_ZONE_ID).that(zones).asList().isEmpty();
5316      }
5317  
5318      @Test
getMirrorAudioZonesForMirrorRequest_withMirroringEnabled()5319      public void getMirrorAudioZonesForMirrorRequest_withMirroringEnabled() throws Exception {
5320          CarAudioService service = setUpAudioService();
5321          TestAudioZonesMirrorStatusCallbackCallback callback =
5322                  getAudioZonesMirrorStatusCallback(service);
5323          assignOccupantToAudioZones();
5324          long requestId = service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
5325          callback.waitForCallback();
5326  
5327          int[] zones = service.getMirrorAudioZonesForMirrorRequest(requestId);
5328  
5329          expectWithMessage("Mirroring zones for mirror request %s", requestId).that(zones).asList()
5330                  .containsExactly(TEST_REAR_LEFT_ZONE_ID, TEST_REAR_RIGHT_ZONE_ID);
5331      }
5332  
5333      @Test
getMirrorAudioZonesForMirrorRequest_afterDisableMirror()5334      public void getMirrorAudioZonesForMirrorRequest_afterDisableMirror() throws Exception {
5335          CarAudioService service = setUpAudioService();
5336          TestAudioZonesMirrorStatusCallbackCallback callback =
5337                  getAudioZonesMirrorStatusCallback(service);
5338          assignOccupantToAudioZones();
5339          long requestId = service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
5340          callback.waitForCallback();
5341          callback.reset(1);
5342          service.disableAudioMirror(requestId);
5343          callback.waitForCallback();
5344  
5345          int[] zones = service.getMirrorAudioZonesForMirrorRequest(TEST_REAR_RIGHT_ZONE_ID);
5346  
5347          expectWithMessage("Mirroring zones for mirror request %s after disabling mirroring",
5348                  requestId).that(zones).asList().isEmpty();
5349      }
5350  
5351      @Test
getMirrorAudioZonesForMirrorRequest_afterPassengerLogout()5352      public void getMirrorAudioZonesForMirrorRequest_afterPassengerLogout() throws Exception {
5353          CarAudioService service = setUpAudioService();
5354          TestAudioZonesMirrorStatusCallbackCallback callback =
5355                  getAudioZonesMirrorStatusCallback(service);
5356          assignOccupantToAudioZones();
5357          long requestId = service.enableMirrorForAudioZones(TEST_MIRROR_AUDIO_ZONES);
5358          callback.waitForCallback();
5359          callback.reset(1);
5360          simulateLogoutRightPassengers();
5361          callback.waitForCallback();
5362  
5363          int[] zones = service.getMirrorAudioZonesForMirrorRequest(requestId);
5364  
5365          expectWithMessage("Mirroring zones for mirror request %s after logout",
5366                  TEST_REAR_RIGHT_ZONE_ID).that(zones).asList().isEmpty();
5367      }
5368  
5369      @Test
onAudioVolumeGroupChanged_dispatchCallbackEvent()5370      public void onAudioVolumeGroupChanged_dispatchCallbackEvent() throws Exception {
5371          CarAudioService useCoreAudioCarAudioService =
5372                  setUpCarAudioServiceUsingCoreAudioRoutingAndVolume();
5373          int musicIndex = useCoreAudioCarAudioService.getGroupVolume(
5374                  PRIMARY_AUDIO_ZONE, CoreAudioRoutingUtils.MUSIC_CAR_GROUP_ID);
5375          // Report a volume change
5376          when(mAudioManager.getVolumeIndexForAttributes(eq(CoreAudioRoutingUtils.MUSIC_ATTRIBUTES)))
5377                  .thenReturn(musicIndex + 1);
5378          when(mAudioManager.getLastAudibleVolumeForVolumeGroup(CoreAudioRoutingUtils.MUSIC_GROUP_ID))
5379                  .thenReturn(musicIndex + 1);
5380          when(mAudioManager.isVolumeGroupMuted(CoreAudioRoutingUtils.MUSIC_GROUP_ID))
5381                  .thenReturn(false);
5382  
5383          useCoreAudioCarAudioService.onAudioVolumeGroupChanged(PRIMARY_AUDIO_ZONE,
5384                  CoreAudioRoutingUtils.MUSIC_GROUP_NAME, /* flags= */ 0);
5385  
5386          verify(mCarVolumeCallbackHandler)
5387                  .onVolumeGroupChange(PRIMARY_AUDIO_ZONE, CoreAudioRoutingUtils.MUSIC_CAR_GROUP_ID,
5388                          FLAG_SHOW_UI | FLAG_PLAY_SOUND);
5389      }
5390  
5391      @Test
onAudioVolumeGroupChanged_noDispatchCallbackEvent_whenAlreadySynced()5392      public void onAudioVolumeGroupChanged_noDispatchCallbackEvent_whenAlreadySynced()
5393              throws Exception {
5394          CarAudioService useCoreAudioCarAudioService =
5395                  setUpCarAudioServiceUsingCoreAudioRoutingAndVolume();
5396          useCoreAudioCarAudioService.setGroupVolume(PRIMARY_AUDIO_ZONE,
5397                  CoreAudioRoutingUtils.MUSIC_CAR_GROUP_ID, CoreAudioRoutingUtils.MUSIC_AM_INIT_INDEX,
5398                  /* flags= */ 0);
5399          reset(mCarVolumeCallbackHandler);
5400  
5401          useCoreAudioCarAudioService.onAudioVolumeGroupChanged(PRIMARY_AUDIO_ZONE,
5402                  CoreAudioRoutingUtils.MUSIC_GROUP_NAME, /* flags= */ 0);
5403  
5404          verify(mCarVolumeCallbackHandler, never())
5405                  .onVolumeGroupChange(anyInt(), anyInt(), anyInt());
5406      }
5407  
5408      @Test
onAudioVolumeGroupChanged_dispatchCallbackEvent_whenMuted()5409      public void onAudioVolumeGroupChanged_dispatchCallbackEvent_whenMuted() throws Exception {
5410          CarAudioService useCoreAudioCarAudioService =
5411                  setUpCarAudioServiceUsingCoreAudioRoutingAndVolume();
5412          // Report a mute change
5413          when(mAudioManager.getVolumeIndexForAttributes(eq(CoreAudioRoutingUtils.MUSIC_ATTRIBUTES)))
5414                  .thenReturn(CoreAudioRoutingUtils.MUSIC_MIN_INDEX);
5415          when(mAudioManager.isVolumeGroupMuted(CoreAudioRoutingUtils.MUSIC_GROUP_ID))
5416                  .thenReturn(true);
5417  
5418          useCoreAudioCarAudioService.onAudioVolumeGroupChanged(PRIMARY_AUDIO_ZONE,
5419                  CoreAudioRoutingUtils.MUSIC_GROUP_NAME, /* flags= */ 0);
5420  
5421          verify(mCarVolumeCallbackHandler).onGroupMuteChange(PRIMARY_AUDIO_ZONE,
5422                  CoreAudioRoutingUtils.MUSIC_CAR_GROUP_ID, FLAG_SHOW_UI);
5423      }
5424  
5425      @Test
onAudioVolumeGroupChanged_withInvalidVolumeGroupName()5426      public void onAudioVolumeGroupChanged_withInvalidVolumeGroupName() throws Exception {
5427          CarAudioService useCoreAudioCarAudioService =
5428                  setUpCarAudioServiceUsingCoreAudioRoutingAndVolume();
5429  
5430          useCoreAudioCarAudioService.onAudioVolumeGroupChanged(PRIMARY_AUDIO_ZONE,
5431                  CoreAudioRoutingUtils.INVALID_GROUP_NAME, /* flags= */ 0);
5432  
5433          verify(mCarVolumeCallbackHandler, never()).onVolumeGroupChange(eq(PRIMARY_AUDIO_ZONE),
5434                  anyInt(), anyInt());
5435      }
5436  
5437      @Test
callbackVolumeGroupEvent_withEmptyEventList()5438      public void callbackVolumeGroupEvent_withEmptyEventList() throws Exception {
5439          CarAudioService service = setUpAudioService();
5440          TestCarVolumeEventCallback volumeEventCallback =
5441                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
5442          service.registerCarVolumeEventCallback(volumeEventCallback);
5443  
5444          service.callbackVolumeGroupEvent(Collections.EMPTY_LIST);
5445  
5446          expectWithMessage("Volume group event callback reception status for empty event list")
5447                  .that(volumeEventCallback.waitForCallback()).isFalse();
5448      }
5449  
5450      @Test
onVolumeGroupEvent_withVolumeEvent_triggersCallback()5451      public void onVolumeGroupEvent_withVolumeEvent_triggersCallback() throws Exception {
5452          CarAudioService service = setUpAudioService();
5453          TestCarVolumeEventCallback volumeEventCallback =
5454                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
5455          service.registerCarVolumeEventCallback(volumeEventCallback);
5456  
5457          service.onVolumeGroupEvent(List.of(mTestCarVolumeGroupEvent));
5458  
5459          expectWithMessage("Volume event callback reception status")
5460                  .that(volumeEventCallback.waitForCallback()).isTrue();
5461          verify(mCarVolumeCallbackHandler, never()).onGroupMuteChange(anyInt(), anyInt(), anyInt());
5462          verify(mCarVolumeCallbackHandler)
5463                  .onVolumeGroupChange(PRIMARY_AUDIO_ZONE, CoreAudioRoutingUtils.MUSIC_CAR_GROUP_ID,
5464                          /* flags= */ 0);
5465          expectWithMessage("Volume events count after volume event")
5466                  .that(volumeEventCallback.getVolumeGroupEvents()).hasSize(1);
5467          CarVolumeGroupEvent groupEvent = volumeEventCallback.getVolumeGroupEvents().get(0);
5468          expectWithMessage("Volume event type after volume event")
5469                  .that(groupEvent.getEventTypes())
5470                  .isEqualTo(CarVolumeGroupEvent.EVENT_TYPE_VOLUME_GAIN_INDEX_CHANGED);
5471          expectWithMessage("Volume group infos after unmute")
5472                  .that(groupEvent.getCarVolumeGroupInfos())
5473                  .containsExactly(mTestPrimaryZoneUmMutedVolueInfo0);
5474      }
5475  
5476      @Test
onVolumeGroupEvent_withMuteEvent_triggersCallback()5477      public void onVolumeGroupEvent_withMuteEvent_triggersCallback() throws Exception {
5478          CarAudioService service = setUpAudioService();
5479          TestCarVolumeEventCallback volumeEventCallback =
5480                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
5481          service.registerCarVolumeEventCallback(volumeEventCallback);
5482  
5483          service.onVolumeGroupEvent(List.of(mTestCarMuteGroupEvent));
5484  
5485          expectWithMessage("Volume event callback reception status")
5486                  .that(volumeEventCallback.waitForCallback()).isTrue();
5487          verify(mCarVolumeCallbackHandler, never())
5488                  .onVolumeGroupChange(anyInt(), anyInt(), anyInt());
5489          verify(mCarVolumeCallbackHandler)
5490                  .onGroupMuteChange(PRIMARY_AUDIO_ZONE, CoreAudioRoutingUtils.MUSIC_CAR_GROUP_ID,
5491                          /* flags= */ 0);
5492          expectWithMessage("Volume events count after mute event")
5493                  .that(volumeEventCallback.getVolumeGroupEvents()).hasSize(1);
5494          CarVolumeGroupEvent groupEvent = volumeEventCallback.getVolumeGroupEvents().get(0);
5495          expectWithMessage("Volume event type after mute event")
5496                  .that(groupEvent.getEventTypes())
5497                  .isEqualTo(CarVolumeGroupEvent.EVENT_TYPE_MUTE_CHANGED);
5498          expectWithMessage("Volume group infos after mute event")
5499                  .that(groupEvent.getCarVolumeGroupInfos())
5500                  .containsExactly(mTestPrimaryZoneUmMutedVolueInfo0);
5501      }
5502  
5503      @Test
onVolumeGroupEvent_withoutMuteOrVolumeEvent_triggersCallback()5504      public void onVolumeGroupEvent_withoutMuteOrVolumeEvent_triggersCallback()
5505              throws Exception {
5506          CarAudioService service = setUpAudioService();
5507          TestCarVolumeEventCallback volumeEventCallback =
5508                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
5509          service.registerCarVolumeEventCallback(volumeEventCallback);
5510  
5511          service.onVolumeGroupEvent(List.of(mTestCarZoneReconfigurationEvent));
5512  
5513          expectWithMessage("Volume event callback reception status")
5514                  .that(volumeEventCallback.waitForCallback()).isTrue();
5515          verify(mCarVolumeCallbackHandler, never())
5516                  .onVolumeGroupChange(anyInt(), anyInt(), anyInt());
5517          verify(mCarVolumeCallbackHandler, never()).onGroupMuteChange(anyInt(), anyInt(), anyInt());
5518          expectWithMessage("Volume events count after reconfiguration event")
5519                  .that(volumeEventCallback.getVolumeGroupEvents()).hasSize(1);
5520          CarVolumeGroupEvent groupEvent = volumeEventCallback.getVolumeGroupEvents().get(0);
5521          expectWithMessage("Volume event type after reconfiguration event")
5522                  .that(groupEvent.getEventTypes())
5523                  .isEqualTo(CarVolumeGroupEvent.EVENT_TYPE_ZONE_CONFIGURATION_CHANGED);
5524          expectWithMessage("Volume group infos after reconfiguration event")
5525                  .that(groupEvent.getCarVolumeGroupInfos())
5526                  .containsExactly(mTestPrimaryZoneUmMutedVolueInfo0);
5527      }
5528  
5529      @Test
setMuted_whenUnmuted_onActivation_triggersCallback()5530      public void setMuted_whenUnmuted_onActivation_triggersCallback() throws Exception {
5531          CarAudioService service = setUpAudioService();
5532          TestCarVolumeEventCallback volumeEventCallback =
5533                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
5534          service.registerCarVolumeEventCallback(volumeEventCallback);
5535  
5536          service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
5537                  /* mute= */ true, TEST_FLAGS);
5538  
5539          verify(mCarVolumeCallbackHandler).onGroupMuteChange(PRIMARY_AUDIO_ZONE,
5540                  TEST_PRIMARY_ZONE_GROUP_0, TEST_FLAGS);
5541          expectWithMessage("Volume event callback reception status after mute")
5542                  .that(volumeEventCallback.waitForCallback()).isTrue();
5543          expectWithMessage("Volume events count after mute")
5544                  .that(volumeEventCallback.getVolumeGroupEvents()).hasSize(1);
5545          CarVolumeGroupEvent groupEvent = volumeEventCallback.getVolumeGroupEvents().get(0);
5546          expectWithMessage("Volume event type after mute")
5547                  .that(groupEvent.getEventTypes())
5548                  .isEqualTo(CarVolumeGroupEvent.EVENT_TYPE_MUTE_CHANGED);
5549          expectWithMessage("Volume group infos after mute")
5550                  .that(groupEvent.getCarVolumeGroupInfos())
5551                  .containsExactly(mTestPrimaryZoneVolumeInfo0);
5552      }
5553  
5554      @Test
setMuted_whenUnmuted_onDeactivation_doesNotTriggerCallback()5555      public void setMuted_whenUnmuted_onDeactivation_doesNotTriggerCallback() throws Exception {
5556          CarAudioService service = setUpAudioService();
5557          TestCarVolumeEventCallback volumeEventCallback =
5558                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
5559          service.registerCarVolumeEventCallback(volumeEventCallback);
5560  
5561          service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
5562                  /* mute= */ false, TEST_FLAGS);
5563  
5564          verify(mCarVolumeCallbackHandler, never()).onGroupMuteChange(anyInt(), anyInt(), anyInt());
5565          expectWithMessage("Volume event callback reception status")
5566                  .that(volumeEventCallback.waitForCallback()).isFalse();
5567      }
5568  
5569      @Test
setMuted_whenMuted_onDeactivation_triggersCallback()5570      public void setMuted_whenMuted_onDeactivation_triggersCallback() throws Exception {
5571          CarAudioService service = setUpAudioService();
5572          TestCarVolumeEventCallback volumeEventCallback =
5573                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
5574          service.registerCarVolumeEventCallback(volumeEventCallback);
5575          service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
5576                  /* mute= */ true, TEST_FLAGS);
5577          resetVolumeCallbacks(volumeEventCallback);
5578  
5579          service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
5580                  /* mute= */ false, TEST_FLAGS);
5581  
5582          verify(mCarVolumeCallbackHandler).onGroupMuteChange(PRIMARY_AUDIO_ZONE,
5583                  TEST_PRIMARY_ZONE_GROUP_0, TEST_FLAGS);
5584          expectWithMessage("Volume event callback reception status after unmute")
5585                  .that(volumeEventCallback.waitForCallback()).isTrue();
5586          expectWithMessage("Volume events count after mute")
5587                  .that(volumeEventCallback.getVolumeGroupEvents()).hasSize(1);
5588          CarVolumeGroupEvent groupEvent = volumeEventCallback.getVolumeGroupEvents().get(0);
5589          expectWithMessage("Volume event type after unmute")
5590                  .that(groupEvent.getEventTypes())
5591                  .isEqualTo(CarVolumeGroupEvent.EVENT_TYPE_MUTE_CHANGED);
5592          expectWithMessage("Volume group infos after unmute")
5593                  .that(groupEvent.getCarVolumeGroupInfos())
5594                  .containsExactly(mTestPrimaryZoneUmMutedVolueInfo0);
5595      }
5596  
5597      @Test
setUnmuted_whenMutedBySystem_triggersCallback()5598      public void setUnmuted_whenMutedBySystem_triggersCallback() throws Exception {
5599          CarAudioService service = setUpAudioService();
5600          TestCarVolumeEventCallback volumeEventCallback =
5601                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
5602          service.registerCarVolumeEventCallback(volumeEventCallback);
5603          CarAudioGainConfigInfo primaryAudioZoneCarGain = createCarAudioGainConfigInfo(
5604                  PRIMARY_AUDIO_ZONE, MEDIA_TEST_DEVICE, TEST_GAIN_INDEX);
5605          HalAudioGainCallback halAudioGainCallback = getHalAudioGainCallback();
5606          halAudioGainCallback.onAudioDeviceGainsChanged(List.of(Reasons.TCU_MUTE),
5607                  List.of(primaryAudioZoneCarGain));
5608          resetVolumeCallbacks(volumeEventCallback);
5609  
5610          service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
5611                  /* mute= */ false, TEST_FLAGS);
5612  
5613          verify(mCarVolumeCallbackHandler).onGroupMuteChange(PRIMARY_AUDIO_ZONE,
5614                  TEST_PRIMARY_ZONE_GROUP_0, TEST_FLAGS);
5615          expectWithMessage("Volume event callback reception status after unmute when muted by "
5616                  + "system").that(volumeEventCallback.waitForCallback()).isTrue();
5617          expectWithMessage("Volume events count after mute when muted by system")
5618                  .that(volumeEventCallback.getVolumeGroupEvents()).hasSize(1);
5619          CarVolumeGroupEvent groupEvent = volumeEventCallback.getVolumeGroupEvents().get(0);
5620          expectWithMessage("Volume event type after unmute when muted by system")
5621                  .that(groupEvent.getEventTypes())
5622                  .isEqualTo(CarVolumeGroupEvent.EVENT_TYPE_MUTE_CHANGED);
5623      }
5624  
5625      @Test
setMuted_whenMutedByApiAndSystem_doesNotTriggerCallback()5626      public void setMuted_whenMutedByApiAndSystem_doesNotTriggerCallback() throws Exception {
5627          CarAudioService service = setUpAudioService();
5628          TestCarVolumeEventCallback volumeEventCallback =
5629                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
5630          service.registerCarVolumeEventCallback(volumeEventCallback);
5631          service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0, /* mute= */ true,
5632                  TEST_FLAGS);
5633          resetVolumeCallbacks(volumeEventCallback);
5634          CarAudioGainConfigInfo primaryAudioZoneCarGain = createCarAudioGainConfigInfo(
5635                  PRIMARY_AUDIO_ZONE, MEDIA_TEST_DEVICE, TEST_GAIN_INDEX);
5636          HalAudioGainCallback halAudioGainCallback = getHalAudioGainCallback();
5637          halAudioGainCallback.onAudioDeviceGainsChanged(List.of(Reasons.TCU_MUTE),
5638                  List.of(primaryAudioZoneCarGain));
5639          resetVolumeCallbacks(volumeEventCallback);
5640  
5641          service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0, /* mute= */ true,
5642                  TEST_FLAGS);
5643  
5644          verify(mCarVolumeCallbackHandler, never()).onGroupMuteChange(anyInt(), anyInt(), anyInt());
5645          expectWithMessage("Volume event callback reception status after mute when muted by "
5646                  + "both API and system").that(volumeEventCallback.waitForCallback()).isFalse();
5647      }
5648  
5649      @Test
setMuted_whenMuted_onActivation_doesNotTriggerCallback()5650      public void setMuted_whenMuted_onActivation_doesNotTriggerCallback() throws Exception {
5651          CarAudioService service = setUpAudioService();
5652          TestCarVolumeEventCallback volumeEventCallback =
5653                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
5654          service.registerCarVolumeEventCallback(volumeEventCallback);
5655          service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
5656                  /* mute= */ true, TEST_FLAGS);
5657          resetVolumeCallbacks(volumeEventCallback);
5658  
5659          service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
5660                  /* mute= */ true, TEST_FLAGS);
5661  
5662          verify(mCarVolumeCallbackHandler, never()).onGroupMuteChange(anyInt(), anyInt(), anyInt());
5663          expectWithMessage("Volume event callback reception status")
5664                  .that(volumeEventCallback.waitForCallback()).isFalse();
5665      }
5666  
5667      @Test
handleActivationVolumeWithAudioAttributes_withMultipleAudioAttributes()5668      public void handleActivationVolumeWithAudioAttributes_withMultipleAudioAttributes()
5669              throws Exception {
5670          mSetFlagsRule.enableFlags(Flags.FLAG_CAR_AUDIO_MIN_MAX_ACTIVATION_VOLUME);
5671          CarAudioService service = setUpAudioServiceWithMinMaxActivationVolume(/* enabled= */ true);
5672          TestCarVolumeEventCallback volumeEventCallback =
5673                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
5674          service.registerCarVolumeEventCallback(volumeEventCallback);
5675          int currentConfigId = service.getCurrentAudioZoneConfigInfo(PRIMARY_AUDIO_ZONE)
5676                  .getConfigId();
5677          int mediaMaxActivationGainIndex = service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE,
5678                  TEST_PRIMARY_ZONE_GROUP_0).getMaxActivationVolumeGainIndex();
5679          setVolumeForGroup(service, volumeEventCallback, PRIMARY_AUDIO_ZONE,
5680                  TEST_PRIMARY_ZONE_GROUP_0, mediaMaxActivationGainIndex + 1);
5681          int navMinActivationGainIndex = service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE,
5682                  TEST_PRIMARY_ZONE_GROUP_1).getMinActivationVolumeGainIndex();
5683          setVolumeForGroup(service, volumeEventCallback, PRIMARY_AUDIO_ZONE,
5684                  TEST_PRIMARY_ZONE_GROUP_1, navMinActivationGainIndex - 1);
5685  
5686          service.handleActivationVolumeWithActivationInfos(List.of(
5687                  new CarAudioPlaybackMonitor.ActivationInfo(TEST_PRIMARY_ZONE_GROUP_0,
5688                          CarActivationVolumeConfig.ACTIVATION_VOLUME_ON_BOOT),
5689                  new CarAudioPlaybackMonitor.ActivationInfo(TEST_PRIMARY_ZONE_GROUP_1,
5690                          CarActivationVolumeConfig.ACTIVATION_VOLUME_ON_BOOT)),
5691                  PRIMARY_AUDIO_ZONE, currentConfigId);
5692  
5693          expectWithMessage("Media volume for above-activation gain index")
5694                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0))
5695                  .isEqualTo(mediaMaxActivationGainIndex);
5696          expectWithMessage("Navigation volume for below-activation gain index")
5697                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_1))
5698                  .isEqualTo(navMinActivationGainIndex);
5699          verify(mCarVolumeCallbackHandler).onVolumeGroupChange(eq(PRIMARY_AUDIO_ZONE),
5700                  eq(TEST_PRIMARY_ZONE_GROUP_0), anyInt());
5701          verify(mCarVolumeCallbackHandler).onVolumeGroupChange(eq(PRIMARY_AUDIO_ZONE),
5702                  eq(TEST_PRIMARY_ZONE_GROUP_1), anyInt());
5703          expectWithMessage("Volume event callback for volume out of activation gain index range")
5704                  .that(volumeEventCallback.waitForCallback()).isTrue();
5705          expectWithMessage("Volume events count after activation gain index adjustment")
5706                  .that(volumeEventCallback.getVolumeGroupEvents()).hasSize(1);
5707          CarVolumeGroupEvent groupEvent = volumeEventCallback.getVolumeGroupEvents().get(0);
5708          expectWithMessage("Volume event type after activation gain index adjustment")
5709                  .that(groupEvent.getEventTypes())
5710                  .isEqualTo(CarVolumeGroupEvent.EVENT_TYPE_VOLUME_GAIN_INDEX_CHANGED);
5711          expectWithMessage("Volume group info after activation gain index adjustment"
5712                  + " adjustment").that(groupEvent.getCarVolumeGroupInfos()).containsExactly(
5713                          service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0),
5714                  service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_1));
5715      }
5716  
5717      @Test
handleActivationVolumeWithAudioAttributes_withNonCurrentZoneConfig()5718      public void handleActivationVolumeWithAudioAttributes_withNonCurrentZoneConfig()
5719              throws Exception {
5720          mSetFlagsRule.enableFlags(Flags.FLAG_CAR_AUDIO_MIN_MAX_ACTIVATION_VOLUME);
5721          CarAudioService service = setUpAudioServiceWithMinMaxActivationVolume(/* enabled= */ true);
5722          TestCarVolumeEventCallback volumeEventCallback =
5723                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
5724          service.registerCarVolumeEventCallback(volumeEventCallback);
5725          int nonCurrentConfigId = getZoneConfigToSwitch(service, TEST_REAR_LEFT_ZONE_ID)
5726                  .getConfigId();
5727          int mediaGainIndexAboveMaxActivation = service.getVolumeGroupInfo(TEST_REAR_LEFT_ZONE_ID,
5728                  SECONDARY_ZONE_VOLUME_GROUP_ID).getMaxActivationVolumeGainIndex() + 1;
5729          setVolumeForGroup(service, volumeEventCallback, TEST_REAR_LEFT_ZONE_ID,
5730                  SECONDARY_ZONE_VOLUME_GROUP_ID, mediaGainIndexAboveMaxActivation);
5731  
5732          service.handleActivationVolumeWithActivationInfos(List.of(
5733                          new CarAudioPlaybackMonitor.ActivationInfo(TEST_REAR_LEFT_ZONE_ID,
5734                                  CarActivationVolumeConfig.ACTIVATION_VOLUME_ON_BOOT)),
5735                  TEST_REAR_LEFT_ZONE_ID, nonCurrentConfigId);
5736  
5737          verify(mCarVolumeCallbackHandler, never()).onVolumeGroupChange(eq(TEST_REAR_LEFT_ZONE_ID),
5738                  eq(SECONDARY_ZONE_VOLUME_GROUP_ID), anyInt());
5739          expectWithMessage("Volume event callback for non-current zone config activation volume")
5740                  .that(volumeEventCallback.waitForCallback()).isFalse();
5741      }
5742  
5743      @Test
onPlaybackConfigChanged_withActivationVolumeFlagDisabled()5744      public void onPlaybackConfigChanged_withActivationVolumeFlagDisabled() throws Exception {
5745          mSetFlagsRule.disableFlags(Flags.FLAG_CAR_AUDIO_MIN_MAX_ACTIVATION_VOLUME);
5746          CarAudioService service = setUpAudioServiceWithMinMaxActivationVolume(/* enabled= */ true);
5747          AudioPlaybackCallback callback = getCarAudioPlaybackCallback();
5748          TestCarVolumeEventCallback volumeEventCallback =
5749                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
5750          service.registerCarVolumeEventCallback(volumeEventCallback);
5751          int gainIndex = service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE,
5752                  TEST_PRIMARY_ZONE_GROUP_0).getMaxActivationVolumeGainIndex() + 1;
5753          setVolumeForGroup(service, volumeEventCallback, PRIMARY_AUDIO_ZONE,
5754                  TEST_PRIMARY_ZONE_GROUP_0, gainIndex);
5755  
5756          callback.onPlaybackConfigChanged(List.of(new AudioPlaybackConfigurationBuilder()
5757                  .setUsage(USAGE_MEDIA).setDeviceAddress(MEDIA_TEST_DEVICE)
5758                  .setClientUid(TEST_PLAYBACK_UID).build()));
5759  
5760          expectWithMessage("Playback group volume with activation volume flag disabled")
5761                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0))
5762                  .isEqualTo(gainIndex);
5763          verify(mCarVolumeCallbackHandler, never()).onVolumeGroupChange(eq(PRIMARY_AUDIO_ZONE),
5764                  eq(TEST_PRIMARY_ZONE_GROUP_0), anyInt());
5765          expectWithMessage("No volume event callback for activation volume flag disabled")
5766                  .that(volumeEventCallback.waitForCallback()).isFalse();
5767      }
5768  
5769      @Test
onPlaybackConfigChanged_withActivationVolumeFeatureDisabled()5770      public void onPlaybackConfigChanged_withActivationVolumeFeatureDisabled() throws Exception {
5771          mSetFlagsRule.disableFlags(Flags.FLAG_CAR_AUDIO_MIN_MAX_ACTIVATION_VOLUME);
5772          CarAudioService service = setUpAudioServiceWithMinMaxActivationVolume(/* enabled= */ false);
5773          AudioPlaybackCallback callback = getCarAudioPlaybackCallback();
5774          TestCarVolumeEventCallback volumeEventCallback =
5775                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
5776          service.registerCarVolumeEventCallback(volumeEventCallback);
5777          int gainIndex = service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE,
5778                  TEST_PRIMARY_ZONE_GROUP_0).getMaxActivationVolumeGainIndex() + 1;
5779          setVolumeForGroup(service, volumeEventCallback, PRIMARY_AUDIO_ZONE,
5780                  TEST_PRIMARY_ZONE_GROUP_0, gainIndex);
5781  
5782          callback.onPlaybackConfigChanged(List.of(new AudioPlaybackConfigurationBuilder()
5783                  .setUsage(USAGE_MEDIA).setDeviceAddress(MEDIA_TEST_DEVICE)
5784                  .setClientUid(TEST_PLAYBACK_UID).build()));
5785  
5786          expectWithMessage("Playback group volume with activation volume feature disabled")
5787                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0))
5788                  .isEqualTo(gainIndex);
5789          verify(mCarVolumeCallbackHandler, never()).onVolumeGroupChange(eq(PRIMARY_AUDIO_ZONE),
5790                  eq(TEST_PRIMARY_ZONE_GROUP_0), anyInt());
5791          expectWithMessage("No volume event callback for activation volume feature disabled")
5792                  .that(volumeEventCallback.waitForCallback()).isFalse();
5793      }
5794  
5795      @Test
onPlaybackConfigChanged_withVolumeAboveMaxActivationVolume()5796      public void onPlaybackConfigChanged_withVolumeAboveMaxActivationVolume() throws Exception {
5797          mSetFlagsRule.enableFlags(Flags.FLAG_CAR_AUDIO_MIN_MAX_ACTIVATION_VOLUME);
5798          CarAudioService service = setUpAudioServiceWithMinMaxActivationVolume(/* enabled= */ true);
5799          AudioPlaybackCallback callback = getCarAudioPlaybackCallback();
5800          TestCarVolumeEventCallback volumeEventCallback =
5801                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
5802          service.registerCarVolumeEventCallback(volumeEventCallback);
5803          int maxActivationVolume = service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE,
5804                  TEST_PRIMARY_ZONE_GROUP_0).getMaxActivationVolumeGainIndex();
5805          setVolumeForGroup(service, volumeEventCallback, PRIMARY_AUDIO_ZONE,
5806                  TEST_PRIMARY_ZONE_GROUP_0, maxActivationVolume + 1);
5807  
5808          callback.onPlaybackConfigChanged(List.of(new AudioPlaybackConfigurationBuilder()
5809                  .setUsage(USAGE_MEDIA).setDeviceAddress(MEDIA_TEST_DEVICE)
5810                  .setClientUid(TEST_PLAYBACK_UID).build()));
5811  
5812          expectWithMessage("Playback group volume for above-activation gain index")
5813                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0))
5814                  .isEqualTo(maxActivationVolume);
5815          verify(mCarVolumeCallbackHandler).onVolumeGroupChange(eq(PRIMARY_AUDIO_ZONE),
5816                  eq(TEST_PRIMARY_ZONE_GROUP_0), anyInt());
5817          expectWithMessage("Volume event callback for above-activation gain index")
5818                  .that(volumeEventCallback.waitForCallback()).isTrue();
5819          expectWithMessage("Volume events count after above-activation gain index adjustment")
5820                  .that(volumeEventCallback.getVolumeGroupEvents()).hasSize(1);
5821          CarVolumeGroupEvent groupEvent = volumeEventCallback.getVolumeGroupEvents().get(0);
5822          expectWithMessage("Volume event type after above-activation gain index adjustment")
5823                  .that(groupEvent.getEventTypes())
5824                  .isEqualTo(CarVolumeGroupEvent.EVENT_TYPE_VOLUME_GAIN_INDEX_CHANGED);
5825          expectWithMessage("Volume group info after above-activation gain index adjustment")
5826                  .that(groupEvent.getCarVolumeGroupInfos()).containsExactly(
5827                          service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0));
5828      }
5829  
5830      @Test
onPlaybackConfigChanged_withVolumeBelowMinActivationVolume()5831      public void onPlaybackConfigChanged_withVolumeBelowMinActivationVolume() throws Exception {
5832          mSetFlagsRule.enableFlags(Flags.FLAG_CAR_AUDIO_MIN_MAX_ACTIVATION_VOLUME);
5833          CarAudioService service = setUpAudioServiceWithMinMaxActivationVolume(/* enabled= */ true);
5834          AudioPlaybackCallback callback = getCarAudioPlaybackCallback();
5835          TestCarVolumeEventCallback volumeEventCallback =
5836                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
5837          service.registerCarVolumeEventCallback(volumeEventCallback);
5838          int minActivationVolume = service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE,
5839                  TEST_PRIMARY_ZONE_GROUP_1).getMinActivationVolumeGainIndex();
5840          setVolumeForGroup(service, volumeEventCallback, PRIMARY_AUDIO_ZONE,
5841                  TEST_PRIMARY_ZONE_GROUP_1, minActivationVolume - 1);
5842  
5843          callback.onPlaybackConfigChanged(List.of(new AudioPlaybackConfigurationBuilder()
5844                  .setUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
5845                  .setDeviceAddress(NAVIGATION_TEST_DEVICE).setClientUid(TEST_PLAYBACK_UID)
5846                  .build()));
5847  
5848          expectWithMessage("Playback group volume for below-activation gain index")
5849                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_1))
5850                  .isEqualTo(minActivationVolume);
5851          verify(mCarVolumeCallbackHandler).onVolumeGroupChange(eq(PRIMARY_AUDIO_ZONE),
5852                  eq(TEST_PRIMARY_ZONE_GROUP_1), anyInt());
5853          expectWithMessage("Volume event callback for below-activation gain index")
5854                  .that(volumeEventCallback.waitForCallback()).isTrue();
5855          expectWithMessage("Volume events count after below-activation gain index adjustment")
5856                  .that(volumeEventCallback.getVolumeGroupEvents()).hasSize(1);
5857          CarVolumeGroupEvent groupEvent = volumeEventCallback.getVolumeGroupEvents().get(0);
5858          expectWithMessage("Volume event type after below-activation gain index adjustment")
5859                  .that(groupEvent.getEventTypes())
5860                  .isEqualTo(CarVolumeGroupEvent.EVENT_TYPE_VOLUME_GAIN_INDEX_CHANGED);
5861          expectWithMessage("Volume group info after below-activation gain index adjustment")
5862                  .that(groupEvent.getCarVolumeGroupInfos()).containsExactly(
5863                          service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_1));
5864      }
5865  
5866      @Test
onPlaybackConfigChanged_withVolumeInActivationVolumeRange()5867      public void onPlaybackConfigChanged_withVolumeInActivationVolumeRange() throws Exception {
5868          mSetFlagsRule.enableFlags(Flags.FLAG_CAR_AUDIO_MIN_MAX_ACTIVATION_VOLUME);
5869          CarAudioService service = setUpAudioServiceWithMinMaxActivationVolume(/* enabled= */ true);
5870          AudioPlaybackCallback callback = getCarAudioPlaybackCallback();
5871          TestCarVolumeEventCallback volumeEventCallback =
5872                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
5873          service.registerCarVolumeEventCallback(volumeEventCallback);
5874          int gainIndexInActivationVolumeRange = service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE,
5875                  TEST_PRIMARY_ZONE_GROUP_0).getMaxActivationVolumeGainIndex() - 1;
5876          setVolumeForGroup(service, volumeEventCallback, PRIMARY_AUDIO_ZONE,
5877                  TEST_PRIMARY_ZONE_GROUP_0, gainIndexInActivationVolumeRange);
5878  
5879          callback.onPlaybackConfigChanged(List.of(new AudioPlaybackConfigurationBuilder()
5880                  .setUsage(USAGE_MEDIA).setDeviceAddress(MEDIA_TEST_DEVICE)
5881                  .setClientUid(TEST_PLAYBACK_UID).build()));
5882  
5883          expectWithMessage("Playback group volume in activation volume range")
5884                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0))
5885                  .isEqualTo(gainIndexInActivationVolumeRange);
5886          verify(mCarVolumeCallbackHandler, never()).onVolumeGroupChange(eq(PRIMARY_AUDIO_ZONE),
5887                  eq(TEST_PRIMARY_ZONE_GROUP_0), anyInt());
5888          expectWithMessage("No volume event callback for no activation volume adjustment")
5889                  .that(volumeEventCallback.waitForCallback()).isFalse();
5890      }
5891  
5892      @Test
onPlaybackConfigChanged_withVolumeGroupMute()5893      public void onPlaybackConfigChanged_withVolumeGroupMute() throws Exception {
5894          mSetFlagsRule.enableFlags(Flags.FLAG_CAR_AUDIO_MIN_MAX_ACTIVATION_VOLUME);
5895          CarAudioService service = setUpAudioServiceWithMinMaxActivationVolume(/* enabled= */ true);
5896          AudioPlaybackCallback callback = getCarAudioPlaybackCallback();
5897          TestCarVolumeEventCallback volumeEventCallback =
5898                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
5899          service.registerCarVolumeEventCallback(volumeEventCallback);
5900          int gainIndexAboveActivationVolume = service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE,
5901                  TEST_PRIMARY_ZONE_GROUP_0).getMaxActivationVolumeGainIndex() + 1;
5902          setVolumeForGroup(service, volumeEventCallback, PRIMARY_AUDIO_ZONE,
5903                  TEST_PRIMARY_ZONE_GROUP_0, gainIndexAboveActivationVolume);
5904          service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
5905                  /* mute= */ true, TEST_FLAGS);
5906          resetVolumeCallbacks(volumeEventCallback);
5907  
5908          callback.onPlaybackConfigChanged(List.of(new AudioPlaybackConfigurationBuilder()
5909                  .setUsage(USAGE_MEDIA).setDeviceAddress(MEDIA_TEST_DEVICE)
5910                  .setClientUid(TEST_PLAYBACK_UID).build()));
5911  
5912          expectWithMessage("Mute state with playback volume higher than max activation volume")
5913                  .that(service.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0))
5914                  .isTrue();
5915          verify(mCarVolumeCallbackHandler, never()).onVolumeGroupChange(eq(PRIMARY_AUDIO_ZONE),
5916                  eq(TEST_PRIMARY_ZONE_GROUP_0), anyInt());
5917          verify(mCarVolumeCallbackHandler, never()).onGroupMuteChange(PRIMARY_AUDIO_ZONE,
5918                  TEST_PRIMARY_ZONE_GROUP_0, TEST_FLAGS);
5919          expectWithMessage("No volume event callback for activation volume when mute")
5920                  .that(volumeEventCallback.waitForCallback()).isFalse();
5921      }
5922  
5923      @Test
onPlaybackConfigChanged_afterZoneConfigSwitched()5924      public void onPlaybackConfigChanged_afterZoneConfigSwitched() throws Exception {
5925          mSetFlagsRule.enableFlags(Flags.FLAG_CAR_AUDIO_MIN_MAX_ACTIVATION_VOLUME);
5926          CarAudioService service = setUpAudioServiceWithMinMaxActivationVolume(/* enabled= */ true);
5927          SwitchAudioZoneConfigCallbackImpl zoneConfigSwitchCallback =
5928                  new SwitchAudioZoneConfigCallbackImpl();
5929          assignOccupantToAudioZones();
5930          AudioPlaybackCallback callback = getCarAudioPlaybackCallback();
5931          TestCarVolumeEventCallback volumeEventCallback =
5932                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
5933          service.registerCarVolumeEventCallback(volumeEventCallback);
5934          int maxActivationVolume = service.getVolumeGroupInfo(TEST_REAR_LEFT_ZONE_ID,
5935                  TEST_SECONDARY_ZONE_GROUP_0).getMaxActivationVolumeGainIndex();
5936          setVolumeForGroup(service, volumeEventCallback, TEST_REAR_LEFT_ZONE_ID,
5937                  TEST_SECONDARY_ZONE_GROUP_0, maxActivationVolume + 1);
5938          createActivePlayback(callback, volumeEventCallback, USAGE_MEDIA,
5939                  SECONDARY_TEST_DEVICE_CONFIG_0, TEST_PLAYBACK_UID);
5940          CarAudioZoneConfigInfo zoneConfigSwitchTo = getZoneConfigToSwitch(service,
5941                  TEST_REAR_LEFT_ZONE_ID);
5942          service.switchZoneToConfig(zoneConfigSwitchTo, zoneConfigSwitchCallback);
5943          zoneConfigSwitchCallback.waitForCallback();
5944          resetVolumeCallbacks(volumeEventCallback);
5945          maxActivationVolume = service.getVolumeGroupInfo(TEST_REAR_LEFT_ZONE_ID,
5946                  TEST_SECONDARY_ZONE_GROUP_0).getMaxActivationVolumeGainIndex();
5947          setVolumeForGroup(service, volumeEventCallback, TEST_REAR_LEFT_ZONE_ID,
5948                  TEST_SECONDARY_ZONE_GROUP_0, maxActivationVolume + 1);
5949  
5950          callback.onPlaybackConfigChanged(List.of(new AudioPlaybackConfigurationBuilder()
5951                  .setUsage(USAGE_MEDIA).setDeviceAddress(SECONDARY_TEST_DEVICE_CONFIG_1_0)
5952                  .setClientUid(TEST_PLAYBACK_UID).build()));
5953  
5954          expectWithMessage("Playback group volume after zone config switch")
5955                  .that(service.getGroupVolume(TEST_REAR_LEFT_ZONE_ID, TEST_SECONDARY_ZONE_GROUP_0))
5956                  .isEqualTo(maxActivationVolume);
5957          verify(mCarVolumeCallbackHandler).onVolumeGroupChange(eq(TEST_REAR_LEFT_ZONE_ID),
5958                  eq(TEST_SECONDARY_ZONE_GROUP_0), anyInt());
5959          expectWithMessage("Volume event callback after zone config switch")
5960                  .that(volumeEventCallback.waitForCallback()).isTrue();
5961          expectWithMessage("Volume events count after zone config switch")
5962                  .that(volumeEventCallback.getVolumeGroupEvents()).hasSize(1);
5963          CarVolumeGroupEvent groupEvent = volumeEventCallback.getVolumeGroupEvents().get(0);
5964          expectWithMessage("Volume event type after zone config switch")
5965                  .that(groupEvent.getEventTypes())
5966                  .isEqualTo(CarVolumeGroupEvent.EVENT_TYPE_VOLUME_GAIN_INDEX_CHANGED);
5967          expectWithMessage("Volume group info after zone config switch")
5968                  .that(groupEvent.getCarVolumeGroupInfos()).containsExactly(
5969                          service.getVolumeGroupInfo(TEST_REAR_LEFT_ZONE_ID,
5970                                  TEST_SECONDARY_ZONE_GROUP_0));
5971      }
5972  
5973      @Test
onPlaybackConfigChanged_afterOccupantZoneConfigChanged()5974      public void onPlaybackConfigChanged_afterOccupantZoneConfigChanged() throws Exception {
5975          mSetFlagsRule.enableFlags(Flags.FLAG_CAR_AUDIO_MIN_MAX_ACTIVATION_VOLUME);
5976          CarAudioService service = setUpAudioServiceWithMinMaxActivationVolume(/* enabled= */ true);
5977          AudioPlaybackCallback callback = getCarAudioPlaybackCallback();
5978          TestCarVolumeEventCallback volumeEventCallback =
5979                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
5980          service.registerCarVolumeEventCallback(volumeEventCallback);
5981          int maxActivationVolume = service.getVolumeGroupInfo(TEST_REAR_LEFT_ZONE_ID,
5982                  TEST_SECONDARY_ZONE_GROUP_0).getMaxActivationVolumeGainIndex();
5983          setVolumeForGroup(service, volumeEventCallback, TEST_REAR_LEFT_ZONE_ID,
5984                  TEST_SECONDARY_ZONE_GROUP_0, maxActivationVolume + 1);
5985          createActivePlayback(callback, volumeEventCallback, USAGE_MEDIA,
5986                  SECONDARY_TEST_DEVICE_CONFIG_0, TEST_PLAYBACK_UID);
5987          callback.onPlaybackConfigChanged(List.of(new AudioPlaybackConfigurationBuilder()
5988                  .setUsage(USAGE_MEDIA).setDeviceAddress(SECONDARY_TEST_DEVICE_CONFIG_0)
5989                  .setClientUid(TEST_PLAYBACK_UID).setInactive().build()));
5990          when(mMockOccupantZoneService.getDriverUserId()).thenReturn(TEST_DRIVER_USER_ID);
5991          when(mMockOccupantZoneService.getUserForOccupant(anyInt()))
5992                  .thenReturn(TEST_REAR_LEFT_USER_ID, TEST_REAR_RIGHT_USER_ID);
5993          ICarOccupantZoneCallback occupantZoneCallback = getOccupantZoneCallback();
5994          occupantZoneCallback.onOccupantZoneConfigChanged(
5995                  CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
5996          setVolumeForGroup(service, volumeEventCallback, TEST_REAR_LEFT_ZONE_ID,
5997                  TEST_SECONDARY_ZONE_GROUP_0, maxActivationVolume + 1);
5998  
5999          callback.onPlaybackConfigChanged(List.of(new AudioPlaybackConfigurationBuilder()
6000                  .setUsage(USAGE_MEDIA).setDeviceAddress(SECONDARY_TEST_DEVICE_CONFIG_0)
6001                  .setClientUid(TEST_PLAYBACK_UID).build()));
6002  
6003          expectWithMessage("Playback group volume after zone user switch")
6004                  .that(service.getGroupVolume(TEST_REAR_LEFT_ZONE_ID, TEST_SECONDARY_ZONE_GROUP_0))
6005                  .isEqualTo(maxActivationVolume);
6006          verify(mCarVolumeCallbackHandler).onVolumeGroupChange(eq(TEST_REAR_LEFT_ZONE_ID),
6007                  eq(TEST_SECONDARY_ZONE_GROUP_0), anyInt());
6008          expectWithMessage("Volume event callback after zone user switch")
6009                  .that(volumeEventCallback.waitForCallback()).isTrue();
6010          expectWithMessage("Volume events count after zone user switch")
6011                  .that(volumeEventCallback.getVolumeGroupEvents()).hasSize(1);
6012          CarVolumeGroupEvent groupEvent = volumeEventCallback.getVolumeGroupEvents().get(0);
6013          expectWithMessage("Volume event type after zone user switch")
6014                  .that(groupEvent.getEventTypes())
6015                  .isEqualTo(CarVolumeGroupEvent.EVENT_TYPE_VOLUME_GAIN_INDEX_CHANGED);
6016          expectWithMessage("Volume group info after zone user switch")
6017                  .that(groupEvent.getCarVolumeGroupInfos()).containsExactly(
6018                          service.getVolumeGroupInfo(TEST_REAR_LEFT_ZONE_ID,
6019                                  TEST_SECONDARY_ZONE_GROUP_0));
6020      }
6021  
6022      @Test
setVolumeGroupMute_withUnMuteAfterPlaybackConfigChangedWhenMute()6023      public void setVolumeGroupMute_withUnMuteAfterPlaybackConfigChangedWhenMute() throws Exception {
6024          mSetFlagsRule.enableFlags(Flags.FLAG_CAR_AUDIO_MIN_MAX_ACTIVATION_VOLUME);
6025          CarAudioService service = setUpAudioServiceWithMinMaxActivationVolume(/* enabled= */ true);
6026          AudioPlaybackCallback callback = getCarAudioPlaybackCallback();
6027          TestCarVolumeEventCallback volumeEventCallback =
6028                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
6029          service.registerCarVolumeEventCallback(volumeEventCallback);
6030          int maxActivationVolume = service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE,
6031                  TEST_PRIMARY_ZONE_GROUP_0).getMaxActivationVolumeGainIndex();
6032          int gainIndexAboveActivationVolume = maxActivationVolume + 1;
6033          service.setGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
6034                  gainIndexAboveActivationVolume, TEST_FLAGS);
6035          resetVolumeCallbacks(volumeEventCallback);
6036          service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
6037                  /* mute= */ true, TEST_FLAGS);
6038          resetVolumeCallbacks(volumeEventCallback);
6039          createActivePlayback(callback, volumeEventCallback, USAGE_MEDIA, MEDIA_TEST_DEVICE,
6040                  TEST_PLAYBACK_UID);
6041  
6042          service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
6043                  /* mute= */ false, TEST_FLAGS);
6044  
6045          expectWithMessage("Mute state after playback changed and unmute")
6046                  .that(service.isVolumeGroupMuted(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0))
6047                  .isFalse();
6048          verify(mCarVolumeCallbackHandler).onGroupMuteChange(PRIMARY_AUDIO_ZONE,
6049                  TEST_PRIMARY_ZONE_GROUP_0, TEST_FLAGS);
6050          expectWithMessage("Volume gain index after playback changed and unmute")
6051                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0))
6052                  .isEqualTo(maxActivationVolume);
6053          verify(mCarVolumeCallbackHandler, never()).onVolumeGroupChange(eq(PRIMARY_AUDIO_ZONE),
6054                  eq(TEST_PRIMARY_ZONE_GROUP_0), anyInt());
6055          expectWithMessage("Volume event callback for activation volume adjustment and unmute")
6056                  .that(volumeEventCallback.waitForCallback()).isTrue();
6057          expectWithMessage("Volume events count for activation volume adjustment and unmute")
6058                  .that(volumeEventCallback.getVolumeGroupEvents()).hasSize(1);
6059          CarVolumeGroupEvent groupEvent = volumeEventCallback.getVolumeGroupEvents().get(0);
6060          expectWithMessage("Volume event type after activation volume adjustment and unmute")
6061                  .that(groupEvent.getEventTypes())
6062                  .isEqualTo(CarVolumeGroupEvent.EVENT_TYPE_MUTE_CHANGED);
6063          expectWithMessage("Volume group info after activation volume adjustment and unmute")
6064                  .that(groupEvent.getCarVolumeGroupInfos()).containsExactly(
6065                          service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0));
6066      }
6067  
6068      @Test
requestHalAudioFocus_withVolumeAboveActivationVolume_adjustsToActivationVolume()6069      public void requestHalAudioFocus_withVolumeAboveActivationVolume_adjustsToActivationVolume()
6070              throws Exception {
6071          mSetFlagsRule.enableFlags(Flags.FLAG_CAR_AUDIO_MIN_MAX_ACTIVATION_VOLUME);
6072          when(mAudioManager.requestAudioFocus(any())).thenReturn(
6073                  AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
6074          CarAudioService service = setUpAudioServiceWithMinMaxActivationVolume(/* enabled= */ true);
6075          TestCarVolumeEventCallback volumeEventCallback =
6076                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
6077          service.registerCarVolumeEventCallback(volumeEventCallback);
6078          int maxActivationVolume = service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE,
6079                  TEST_PRIMARY_ZONE_GROUP_1).getMaxActivationVolumeGainIndex();
6080          setVolumeForGroup(service, volumeEventCallback, PRIMARY_AUDIO_ZONE,
6081                  TEST_PRIMARY_ZONE_GROUP_1, maxActivationVolume + 1);
6082  
6083          requestHalAudioFocus(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE);
6084  
6085          expectWithMessage("Playback group volume for HAL focus and above-activation gain index")
6086                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_1))
6087                  .isEqualTo(maxActivationVolume);
6088          verify(mCarVolumeCallbackHandler).onVolumeGroupChange(eq(PRIMARY_AUDIO_ZONE),
6089                  eq(TEST_PRIMARY_ZONE_GROUP_1), anyInt());
6090          expectWithMessage("Volume event callback for HAL focus and above-activation gain index")
6091                  .that(volumeEventCallback.waitForCallback()).isTrue();
6092          expectWithMessage("Volume events count after HAL focus and above-activation gain"
6093                  + " index adjustment").that(volumeEventCallback.getVolumeGroupEvents())
6094                  .hasSize(1);
6095          CarVolumeGroupEvent groupEvent = volumeEventCallback.getVolumeGroupEvents().get(0);
6096          expectWithMessage("Volume event type after HAL focus and above-activation gain"
6097                  + " index adjustment").that(groupEvent.getEventTypes())
6098                  .isEqualTo(CarVolumeGroupEvent.EVENT_TYPE_VOLUME_GAIN_INDEX_CHANGED);
6099          expectWithMessage("Volume group info after HAL focus and above-activation gain"
6100                  + " index adjustment").that(groupEvent.getCarVolumeGroupInfos()).containsExactly(
6101                          service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_1));
6102      }
6103  
6104      @Test
requestHalAudioFocus_withVolumeInActivationVolumeRange()6105      public void requestHalAudioFocus_withVolumeInActivationVolumeRange()
6106              throws Exception {
6107          mSetFlagsRule.enableFlags(Flags.FLAG_CAR_AUDIO_MIN_MAX_ACTIVATION_VOLUME);
6108          when(mAudioManager.requestAudioFocus(any())).thenReturn(
6109                  AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
6110          CarAudioService service = setUpAudioServiceWithMinMaxActivationVolume(/* enabled= */ true);
6111          TestCarVolumeEventCallback volumeEventCallback =
6112                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
6113          service.registerCarVolumeEventCallback(volumeEventCallback);
6114          int gainIndexInActivationVolumeRange = service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE,
6115                  TEST_PRIMARY_ZONE_GROUP_1).getMaxActivationVolumeGainIndex() - 1;
6116          setVolumeForGroup(service, volumeEventCallback, PRIMARY_AUDIO_ZONE,
6117                  TEST_PRIMARY_ZONE_GROUP_1, gainIndexInActivationVolumeRange);
6118  
6119          requestHalAudioFocus(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE);
6120  
6121          expectWithMessage("Playback group volume for HAL focus in activation volume index range")
6122                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_1))
6123                  .isEqualTo(gainIndexInActivationVolumeRange);
6124          verify(mCarVolumeCallbackHandler, never()).onVolumeGroupChange(eq(PRIMARY_AUDIO_ZONE),
6125                  eq(TEST_PRIMARY_ZONE_GROUP_1), anyInt());
6126          expectWithMessage("No volume event callback for HAL focus in activation volume"
6127                  + " index range").that(volumeEventCallback.waitForCallback()).isFalse();
6128      }
6129  
6130      @Test
onCallStateChanged_withOffHookStateAndVolumeBelowMinActivationVolume()6131      public void onCallStateChanged_withOffHookStateAndVolumeBelowMinActivationVolume()
6132              throws Exception {
6133          mSetFlagsRule.enableFlags(Flags.FLAG_CAR_AUDIO_MIN_MAX_ACTIVATION_VOLUME);
6134          CarAudioService service = setUpAudioServiceWithMinMaxActivationVolume(/* enabled= */ true);
6135          TelephonyCallback.CallStateListener callStateListener = getCallStateListener();
6136          TestCarVolumeEventCallback volumeEventCallback =
6137                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
6138          service.registerCarVolumeEventCallback(volumeEventCallback);
6139          int voiceGroupId = service.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE,
6140                  USAGE_VOICE_COMMUNICATION);
6141          int minActivationVolume = service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE,
6142                  TEST_PRIMARY_ZONE_GROUP_1).getMinActivationVolumeGainIndex();
6143          setVolumeForGroup(service, volumeEventCallback, PRIMARY_AUDIO_ZONE, voiceGroupId,
6144                  minActivationVolume - 1);
6145  
6146          callStateListener.onCallStateChanged(TelephonyManager.CALL_STATE_OFFHOOK);
6147  
6148          expectWithMessage("Playback group volume for off-hook and below-activation gain index")
6149                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE, voiceGroupId))
6150                  .isEqualTo(minActivationVolume);
6151          verify(mCarVolumeCallbackHandler).onVolumeGroupChange(eq(PRIMARY_AUDIO_ZONE),
6152                  eq(voiceGroupId), anyInt());
6153          expectWithMessage("Volume event callback for off-hook and below-activation gain index")
6154                  .that(volumeEventCallback.waitForCallback()).isTrue();
6155          expectWithMessage("Volume events count for off-hook after below-activation gain index "
6156                  + "adjustment").that(volumeEventCallback.getVolumeGroupEvents()).hasSize(1);
6157          CarVolumeGroupEvent groupEvent = volumeEventCallback.getVolumeGroupEvents().get(0);
6158          expectWithMessage("Volume event type for off-hook after below-activation gain index "
6159                  + "adjustment").that(groupEvent.getEventTypes())
6160                  .isEqualTo(CarVolumeGroupEvent.EVENT_TYPE_VOLUME_GAIN_INDEX_CHANGED);
6161          expectWithMessage("Volume group info for off-hook after below-activation gain index "
6162                  + "adjustment").that(groupEvent.getCarVolumeGroupInfos()).containsExactly(
6163                          service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, voiceGroupId));
6164      }
6165  
6166      @Test
onCallStateChanged_withRingingStateAndVolumeBelowMinActivationVolume()6167      public void onCallStateChanged_withRingingStateAndVolumeBelowMinActivationVolume()
6168              throws Exception {
6169          mSetFlagsRule.enableFlags(Flags.FLAG_CAR_AUDIO_MIN_MAX_ACTIVATION_VOLUME);
6170          CarAudioService service = setUpAudioServiceWithMinMaxActivationVolume(/* enabled= */ true);
6171          TelephonyCallback.CallStateListener callStateListener = getCallStateListener();
6172          TestCarVolumeEventCallback volumeEventCallback =
6173                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
6174          service.registerCarVolumeEventCallback(volumeEventCallback);
6175          int ringGroupId = service.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE,
6176                  USAGE_NOTIFICATION_RINGTONE);
6177          int minActivationVolume = service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE,
6178                  TEST_PRIMARY_ZONE_GROUP_1).getMinActivationVolumeGainIndex();
6179          setVolumeForGroup(service, volumeEventCallback, PRIMARY_AUDIO_ZONE, ringGroupId,
6180                  minActivationVolume - 1);
6181  
6182          callStateListener.onCallStateChanged(TelephonyManager.CALL_STATE_RINGING);
6183  
6184          expectWithMessage("Playback group volume for ringing and below-activation gain index")
6185                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE, ringGroupId))
6186                  .isEqualTo(minActivationVolume);
6187          verify(mCarVolumeCallbackHandler).onVolumeGroupChange(eq(PRIMARY_AUDIO_ZONE),
6188                  eq(ringGroupId), anyInt());
6189          expectWithMessage("Volume event callback for ringing and below-activation gain index")
6190                  .that(volumeEventCallback.waitForCallback()).isTrue();
6191          expectWithMessage("Volume events count for ringing after below-activation gain index "
6192                  + "adjustment").that(volumeEventCallback.getVolumeGroupEvents()).hasSize(1);
6193          CarVolumeGroupEvent groupEvent = volumeEventCallback.getVolumeGroupEvents().get(0);
6194          expectWithMessage("Volume event type for ringing after below-activation gain index "
6195                  + "adjustment").that(groupEvent.getEventTypes())
6196                  .isEqualTo(CarVolumeGroupEvent.EVENT_TYPE_VOLUME_GAIN_INDEX_CHANGED);
6197          expectWithMessage("Volume group info for ringing after below-activation gain index "
6198                  + "adjustment").that(groupEvent.getCarVolumeGroupInfos()).containsExactly(
6199                  service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE, ringGroupId));
6200      }
6201  
6202      @Test
onCallStateChanged_withRingingStateAndWithinActivationVolumeRange()6203      public void onCallStateChanged_withRingingStateAndWithinActivationVolumeRange()
6204              throws Exception {
6205          mSetFlagsRule.enableFlags(Flags.FLAG_CAR_AUDIO_MIN_MAX_ACTIVATION_VOLUME);
6206          CarAudioService service = setUpAudioServiceWithMinMaxActivationVolume(/* enabled= */ true);
6207          TelephonyCallback.CallStateListener callStateListener = getCallStateListener();
6208          TestCarVolumeEventCallback volumeEventCallback =
6209                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
6210          service.registerCarVolumeEventCallback(volumeEventCallback);
6211          int ringGroupId = service.getVolumeGroupIdForUsage(PRIMARY_AUDIO_ZONE,
6212                  USAGE_NOTIFICATION_RINGTONE);
6213          int gainIndexInActivationVolumeRange = service.getVolumeGroupInfo(PRIMARY_AUDIO_ZONE,
6214                  TEST_PRIMARY_ZONE_GROUP_0).getMinActivationVolumeGainIndex() + 1;
6215          setVolumeForGroup(service, volumeEventCallback, PRIMARY_AUDIO_ZONE, ringGroupId,
6216                  gainIndexInActivationVolumeRange);
6217  
6218          callStateListener.onCallStateChanged(TelephonyManager.CALL_STATE_RINGING);
6219  
6220          expectWithMessage("Playback group volume for ring state in activation volume index range")
6221                  .that(service.getGroupVolume(PRIMARY_AUDIO_ZONE, ringGroupId))
6222                  .isEqualTo(gainIndexInActivationVolumeRange);
6223          verify(mCarVolumeCallbackHandler, never()).onVolumeGroupChange(eq(PRIMARY_AUDIO_ZONE),
6224                  eq(ringGroupId), anyInt());
6225          expectWithMessage("No volume event callback for ring state in activation volume"
6226                  + " index range").that(volumeEventCallback.waitForCallback()).isFalse();
6227      }
6228  
6229      @Test
unregisterCarVolumeEventCallback_forCarVolumeEventHandler()6230      public void unregisterCarVolumeEventCallback_forCarVolumeEventHandler() throws Exception {
6231          CarAudioService service = setUpAudioServiceWithMinMaxActivationVolume(/* enabled= */ true);
6232          TestCarVolumeEventCallback volumeEventCallback =
6233                  new TestCarVolumeEventCallback(TEST_CALLBACK_TIMEOUT_MS);
6234          service.registerCarVolumeEventCallback(volumeEventCallback);
6235  
6236          service.unregisterCarVolumeEventCallback(volumeEventCallback);
6237  
6238          service.setVolumeGroupMute(PRIMARY_AUDIO_ZONE, TEST_PRIMARY_ZONE_GROUP_0,
6239                  /* mute= */ true, TEST_FLAGS);
6240          expectWithMessage("Volume event callback reception status with callback unregistered")
6241                  .that(volumeEventCallback.waitForCallback()).isFalse();
6242      }
waitForInternalCallback()6243      private void waitForInternalCallback() throws Exception {
6244          CountDownLatch latch = new CountDownLatch(1);
6245          mHandler.post(latch::countDown);
6246          latch.await(TEST_ZONE_CONFIG_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
6247      }
6248  
setUpCarAudioServiceWithoutZoneMapping()6249      private CarAudioService setUpCarAudioServiceWithoutZoneMapping() throws Exception {
6250          setUpTempFileForAudioConfiguration(R.raw.car_audio_configuration_without_zone_mapping);
6251          setUpTempFileForAudioFadeConfiguration(R.raw.car_audio_fade_configuration);
6252          when(mMockAudioService.setUidDeviceAffinity(any(), anyInt(), any(), any()))
6253                  .thenReturn(SUCCESS);
6254          CarAudioService noZoneMappingAudioService = new CarAudioService(mMockContext, mAudioManager,
6255                  mTempCarAudioConfigFile.getFile().getAbsolutePath(), mCarVolumeCallbackHandler,
6256                  /* audioFadeConfigurationPath= */ null);
6257          noZoneMappingAudioService.init();
6258          return noZoneMappingAudioService;
6259      }
6260  
setUpAudioService()6261      private CarAudioService setUpAudioService() throws Exception {
6262          setUpTempFileForAudioConfiguration(R.raw.car_audio_configuration);
6263          setUpTempFileForAudioFadeConfiguration(R.raw.car_audio_fade_configuration);
6264          CarAudioService service = new CarAudioService(mMockContext, mAudioManager,
6265                  mTempCarAudioConfigFile.getFile().getAbsolutePath(), mCarVolumeCallbackHandler,
6266                  mTempCarAudioFadeConfigFile.getFile().getAbsolutePath());
6267          service.init();
6268          return service;
6269      }
6270  
setUpAudioServiceWithoutInit()6271      private CarAudioService setUpAudioServiceWithoutInit() throws Exception {
6272          setUpTempFileForAudioConfiguration(R.raw.car_audio_configuration);
6273          setUpTempFileForAudioFadeConfiguration(R.raw.car_audio_fade_configuration);
6274          CarAudioService service = new CarAudioService(mMockContext, mAudioManager,
6275                  mTempCarAudioConfigFile.getFile().getAbsolutePath(), mCarVolumeCallbackHandler,
6276                  mTempCarAudioFadeConfigFile.getFile().getAbsolutePath());
6277          return service;
6278      }
6279  
setUpAudioServiceWithoutDynamicRouting()6280      private CarAudioService setUpAudioServiceWithoutDynamicRouting() throws Exception {
6281          setUpTempFileForAudioConfiguration(R.raw.car_audio_configuration);
6282          setUpTempFileForAudioFadeConfiguration(R.raw.car_audio_fade_configuration);
6283          when(mMockResources.getBoolean(audioUseDynamicRouting)).thenReturn(false);
6284          CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext, mAudioManager,
6285                  mTempCarAudioConfigFile.getFile().getAbsolutePath(), mCarVolumeCallbackHandler,
6286                  /* audioFadeConfigurationPath= */ null);
6287          nonDynamicAudioService.init();
6288          return nonDynamicAudioService;
6289      }
6290  
setUpAudioServiceWithDisabledResource(int resource)6291      private CarAudioService setUpAudioServiceWithDisabledResource(int resource) throws Exception {
6292          setUpTempFileForAudioConfiguration(R.raw.car_audio_configuration);
6293          setUpTempFileForAudioFadeConfiguration(R.raw.car_audio_fade_configuration);
6294          when(mMockResources.getBoolean(resource)).thenReturn(false);
6295          CarAudioService nonDynamicAudioService = new CarAudioService(mMockContext, mAudioManager,
6296                  mTempCarAudioConfigFile.getFile().getAbsolutePath(), mCarVolumeCallbackHandler,
6297                  mTempCarAudioFadeConfigFile.getFile().getAbsolutePath());
6298          nonDynamicAudioService.init();
6299          return nonDynamicAudioService;
6300      }
6301  
getRegisteredZoneConfigCallback( CarAudioService audioServiceWithDynamicDevices)6302      private static TestAudioZoneConfigurationsChangeCallback getRegisteredZoneConfigCallback(
6303              CarAudioService audioServiceWithDynamicDevices) {
6304          TestAudioZoneConfigurationsChangeCallback configCallback =
6305                  new TestAudioZoneConfigurationsChangeCallback();
6306          audioServiceWithDynamicDevices.registerAudioZoneConfigsChangeCallback(configCallback);
6307          return configCallback;
6308      }
6309  
captureAudioDeviceCallback()6310      private AudioDeviceCallback captureAudioDeviceCallback() {
6311          ArgumentCaptor<AudioDeviceCallback> captor =
6312                  ArgumentCaptor.forClass(AudioDeviceCallback.class);
6313          verify(mAudioManager).registerAudioDeviceCallback(captor.capture(), any());
6314          return captor.getValue();
6315      }
6316  
setUpAudioServiceWithDynamicDevices()6317      private CarAudioService setUpAudioServiceWithDynamicDevices() throws Exception {
6318          setUpTempFileForAudioConfiguration(R.raw.car_audio_configuration_using_dynamic_routing);
6319          setUpTempFileForAudioFadeConfiguration(R.raw.car_audio_fade_configuration);
6320          return setUpAudioServiceWithDynamicDevices(mTempCarAudioConfigFile,
6321                  mTempCarAudioFadeConfigFile);
6322      }
6323  
setUpAudioServiceWithDynamicDevices(TemporaryFile fileAudio, TemporaryFile fileFade)6324      private CarAudioService setUpAudioServiceWithDynamicDevices(TemporaryFile fileAudio,
6325              TemporaryFile fileFade) {
6326          mSetFlagsRule.enableFlags(Flags.FLAG_CAR_AUDIO_DYNAMIC_DEVICES);
6327          when(mMockResources.getBoolean(audioUseCoreVolume)).thenReturn(true);
6328          when(mMockResources.getBoolean(audioUseCoreRouting)).thenReturn(false);
6329          CarAudioService audioServiceWithDynamicDevices = new CarAudioService(mMockContext,
6330                  mAudioManager, fileAudio.getFile().getAbsolutePath(), mCarVolumeCallbackHandler,
6331                  fileFade.getFile().getAbsolutePath());
6332          return audioServiceWithDynamicDevices;
6333      }
6334  
setUpAudioServiceWithMinMaxActivationVolume(boolean enabled)6335      private CarAudioService setUpAudioServiceWithMinMaxActivationVolume(boolean enabled)
6336              throws Exception {
6337          setUpTempFileForAudioConfiguration(R.raw.car_audio_configuration_using_activation_volumes);
6338          setUpTempFileForAudioFadeConfiguration(R.raw.car_audio_fade_configuration);
6339          when(mMockResources.getBoolean(audioUseMinMaxActivationVolume)).thenReturn(enabled);
6340          CarAudioService service = new CarAudioService(mMockContext, mAudioManager,
6341                  mTempCarAudioConfigFile.getFile().getAbsolutePath(), mCarVolumeCallbackHandler,
6342                  mTempCarAudioFadeConfigFile.getFile().getAbsolutePath());
6343          service.init();
6344          return service;
6345      }
6346  
getUpdatedCarAudioZoneConfigInfo( CarAudioZoneConfigInfo previousConfig, CarAudioService service)6347      private CarAudioZoneConfigInfo getUpdatedCarAudioZoneConfigInfo(
6348              CarAudioZoneConfigInfo previousConfig, CarAudioService service) {
6349          List<CarAudioZoneConfigInfo> infos =
6350                  service.getAudioZoneConfigInfos(previousConfig.getZoneId());
6351          CarAudioZoneConfigInfo previousUpdated = infos.stream()
6352                  .filter(i-> i.hasSameConfigInfo(previousConfig)).findFirst().orElseThrow(
6353                          () -> new NoSuchPropertyException("Missing previously selected config"));
6354          return previousUpdated;
6355      }
6356  
getOccupantZoneCallback()6357      private ICarOccupantZoneCallback getOccupantZoneCallback() {
6358          ArgumentCaptor<ICarOccupantZoneCallback> captor =
6359                  ArgumentCaptor.forClass(ICarOccupantZoneCallback.class);
6360          verify(mMockOccupantZoneService).registerCallback(captor.capture());
6361          return captor.getValue();
6362      }
6363  
getAudioServerStateCallback()6364      private AudioServerStateCallback getAudioServerStateCallback() {
6365          ArgumentCaptor<AudioServerStateCallback> captor = ArgumentCaptor.forClass(
6366                  AudioServerStateCallback.class);
6367          verify(mAudioManager).setAudioServerStateCallback(any(), captor.capture());
6368          return captor.getValue();
6369      }
6370  
removeUpToEquals(String command)6371      private String removeUpToEquals(String command) {
6372          return command.replaceAll("^[^=]*=", "");
6373      }
6374  
captureAudioMirrorInfoCommand(int count)6375      private String captureAudioMirrorInfoCommand(int count) {
6376          ArgumentCaptor<String> capture = ArgumentCaptor.forClass(String.class);
6377          verify(mAudioManager, times(count)).setParameters(capture.capture());
6378          return capture.getValue();
6379      }
6380  
getAudioZonesMirrorStatusCallback( CarAudioService service)6381      private TestAudioZonesMirrorStatusCallbackCallback getAudioZonesMirrorStatusCallback(
6382              CarAudioService service) {
6383          TestAudioZonesMirrorStatusCallbackCallback callback =
6384                  new TestAudioZonesMirrorStatusCallbackCallback(/* count= */ 1);
6385          service.registerAudioZonesMirrorStatusCallback(callback);
6386          return callback;
6387      }
6388  
assignOccupantToAudioZones()6389      private void assignOccupantToAudioZones() throws RemoteException {
6390          ICarOccupantZoneCallback occupantZoneCallback = getOccupantZoneCallback();
6391          occupantZoneCallback.onOccupantZoneConfigChanged(
6392                  CarOccupantZoneManager.ZONE_CONFIG_CHANGE_FLAG_USER);
6393      }
6394  
simulateLogoutPassengers()6395      private void simulateLogoutPassengers() throws Exception {
6396          when(mMockOccupantZoneService.getUserForOccupant(TEST_REAR_LEFT_OCCUPANT_ZONE_ID))
6397                  .thenReturn(UserManagerHelper.USER_NULL);
6398          when(mMockOccupantZoneService.getUserForOccupant(TEST_REAR_RIGHT_OCCUPANT_ZONE_ID))
6399                  .thenReturn(UserManagerHelper.USER_NULL);
6400  
6401          assignOccupantToAudioZones();
6402      }
6403  
simulateLogoutRightPassengers()6404      private void simulateLogoutRightPassengers() throws Exception {
6405          when(mMockOccupantZoneService.getUserForOccupant(TEST_REAR_RIGHT_OCCUPANT_ZONE_ID))
6406                  .thenReturn(UserManagerHelper.USER_NULL);
6407  
6408          assignOccupantToAudioZones();
6409      }
6410  
simulatePassengersSwitch()6411      private void simulatePassengersSwitch() throws Exception {
6412          when(mMockOccupantZoneService.getUserForOccupant(TEST_REAR_LEFT_OCCUPANT_ZONE_ID))
6413                  .thenReturn(TEST_REAR_RIGHT_USER_ID);
6414          when(mMockOccupantZoneService.getUserForOccupant(TEST_REAR_RIGHT_OCCUPANT_ZONE_ID))
6415                  .thenReturn(TEST_REAR_LEFT_USER_ID);
6416  
6417          assignOccupantToAudioZones();
6418      }
6419  
createCarAudioGainConfigInfo(int zoneId, String devicePortAddress, int volumeIndex)6420      private CarAudioGainConfigInfo createCarAudioGainConfigInfo(int zoneId,
6421              String devicePortAddress, int volumeIndex) {
6422          AudioGainConfigInfo configInfo = new AudioGainConfigInfo();
6423          configInfo.zoneId = zoneId;
6424          configInfo.devicePortAddress = devicePortAddress;
6425          configInfo.volumeIndex = volumeIndex;
6426          return new CarAudioGainConfigInfo(configInfo);
6427      }
6428  
getHalAudioGainCallback()6429      private HalAudioGainCallback getHalAudioGainCallback() {
6430          ArgumentCaptor<HalAudioGainCallback> captor = ArgumentCaptor.forClass(
6431                  HalAudioGainCallback.class);
6432          verify(mAudioControlWrapperAidl).registerAudioGainCallback(captor.capture());
6433          return captor.getValue();
6434      }
6435  
createHalAudioDeviceInfo(int id, String name, int minVal, int maxVal, int defaultVal, int stepVal, int type, String address)6436      private HalAudioDeviceInfo createHalAudioDeviceInfo(int id, String name, int minVal,
6437              int maxVal, int defaultVal, int stepVal, int type, String address) {
6438          AudioPortDeviceExt deviceExt = new AudioPortDeviceExt();
6439          deviceExt.device = new AudioDevice();
6440          deviceExt.device.type = new AudioDeviceDescription();
6441          deviceExt.device.type.type = type;
6442          deviceExt.device.type.connection = CONNECTION_BUS;
6443          deviceExt.device.address = AudioDeviceAddress.id(address);
6444          AudioPort audioPort = new AudioPort();
6445          audioPort.id = id;
6446          audioPort.name = name;
6447          audioPort.gains = new android.media.audio.common.AudioGain[] {
6448                  new android.media.audio.common.AudioGain() {{
6449                      mode = JOINT;
6450                      minValue = minVal;
6451                      maxValue = maxVal;
6452                      defaultValue = defaultVal;
6453                      stepValue = stepVal;
6454                  }}
6455          };
6456          audioPort.ext = AudioPortExt.device(deviceExt);
6457          return new HalAudioDeviceInfo(audioPort);
6458      }
6459  
getHalModuleChangeCallback()6460      private HalAudioModuleChangeCallback getHalModuleChangeCallback() {
6461          ArgumentCaptor<HalAudioModuleChangeCallback> captor = ArgumentCaptor.forClass(
6462                  HalAudioModuleChangeCallback.class);
6463          verify(mAudioControlWrapperAidl).setModuleChangeCallback(captor.capture());
6464          return captor.getValue();
6465      }
6466  
getCarAudioPlaybackCallback()6467      private AudioPlaybackCallback getCarAudioPlaybackCallback() {
6468          ArgumentCaptor<AudioPlaybackCallback> captor = ArgumentCaptor.forClass(
6469                  AudioPlaybackCallback.class);
6470          verify(mAudioManager).registerAudioPlaybackCallback(captor.capture(), any());
6471          return captor.getValue();
6472      }
6473  
getAudioKeyEventListener()6474      private KeyEventListener getAudioKeyEventListener() {
6475          ArgumentCaptor<KeyEventListener> captor = ArgumentCaptor.forClass(KeyEventListener.class);
6476          verify(mMockCarInputService).registerKeyEventListener(captor.capture(), any());
6477          return captor.getValue();
6478      }
6479  
getCallStateListener()6480      private TelephonyCallback.CallStateListener getCallStateListener() {
6481          ArgumentCaptor<TelephonyCallback> captor =
6482                  ArgumentCaptor.forClass(TelephonyCallback.class);
6483          verify(mMockTelephonyManager).registerTelephonyCallback(any(), captor.capture());
6484          return (TelephonyCallback.CallStateListener) captor.getValue();
6485      }
6486  
requestHalAudioFocus(int usage)6487      private void requestHalAudioFocus(int usage) {
6488          ArgumentCaptor<HalFocusListener> captor =
6489                  ArgumentCaptor.forClass(HalFocusListener.class);
6490          verify(mAudioControlWrapperAidl).registerFocusListener(captor.capture());
6491          HalFocusListener halFocusListener = captor.getValue();
6492          halFocusListener.requestAudioFocus(usageToMetadata(usage), PRIMARY_AUDIO_ZONE,
6493                  AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
6494      }
6495  
mockActivePlayback()6496      private void mockActivePlayback() {
6497          AudioPlaybackCallback callback = getCarAudioPlaybackCallback();
6498          callback.onPlaybackConfigChanged(List.of(getPlaybackConfig()));
6499      }
6500  
getPlaybackConfig()6501      private AudioPlaybackConfiguration getPlaybackConfig() {
6502          AudioAttributes audioAttributes = new AudioAttributes.Builder()
6503                  .setUsage(USAGE_MEDIA).build();
6504          AudioPlaybackConfiguration config = mock(AudioPlaybackConfiguration.class);
6505          when(config.getAudioAttributes()).thenReturn(audioAttributes);
6506          when(config.getAudioDeviceInfo()).thenReturn(mMediaOutputDevice);
6507          when(config.isActive()).thenReturn(true);
6508  
6509          return config;
6510      }
6511  
setUpCarAudioServiceWithoutMirroring()6512      private CarAudioService setUpCarAudioServiceWithoutMirroring() throws Exception {
6513          setUpTempFileForAudioConfiguration(R.raw.car_audio_configuration_without_mirroring);
6514          setUpTempFileForAudioFadeConfiguration(R.raw.car_audio_fade_configuration);
6515          AudioDeviceInfo[] outputDevices = generateOutputDeviceInfos();
6516          when(mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS)).thenReturn(outputDevices);
6517          CarAudioService service = new CarAudioService(mMockContext, mAudioManager,
6518                  mTempCarAudioConfigFile.getFile().getAbsolutePath(), mCarVolumeCallbackHandler,
6519                  mTempCarAudioFadeConfigFile.getFile().getAbsolutePath());
6520          service.init();
6521          return service;
6522      }
6523  
setUpCarAudioServiceWithVersionTwoVolumeList()6524      private CarAudioService setUpCarAudioServiceWithVersionTwoVolumeList() throws Exception {
6525          setUpTempFileForAudioConfiguration(R.raw.car_audio_configuration);
6526          setUpTempFileForAudioFadeConfiguration(R.raw.car_audio_fade_configuration);
6527          when(mMockResources.getInteger(audioVolumeAdjustmentContextsVersion))
6528                  .thenReturn(AUDIO_CONTEXT_PRIORITY_LIST_VERSION_TWO);
6529          CarAudioService service = new CarAudioService(mMockContext, mAudioManager,
6530                  mTempCarAudioConfigFile.getFile().getAbsolutePath(), mCarVolumeCallbackHandler,
6531                  mTempCarAudioFadeConfigFile.getFile().getAbsolutePath());
6532          service.init();
6533          return service;
6534      }
6535  
setUpTempFileForAudioConfiguration(int resource)6536      private void setUpTempFileForAudioConfiguration(int resource) throws Exception {
6537          try (InputStream configurationStream = mContext.getResources().openRawResource(resource)) {
6538              mTempCarAudioConfigFile = new TemporaryFile("xml");
6539              mTempCarAudioConfigFile.write(new String(configurationStream.readAllBytes()));
6540          }
6541      }
6542  
setUpTempFileForAudioFadeConfiguration(int resource)6543      private void setUpTempFileForAudioFadeConfiguration(int resource) throws Exception {
6544          try (InputStream configurationStream = mContext.getResources().openRawResource(resource)) {
6545              mTempCarAudioFadeConfigFile = new TemporaryFile("xml");
6546              mTempCarAudioFadeConfigFile.write(new String(configurationStream.readAllBytes()));
6547          }
6548      }
6549  
setUpCarAudioServiceWithFadeManagerEnabled()6550      private CarAudioService setUpCarAudioServiceWithFadeManagerEnabled() throws Exception {
6551          mSetFlagsRule.enableFlags(FLAG_ENABLE_FADE_MANAGER_CONFIGURATION);
6552          mSetFlagsRule.enableFlags(Flags.FLAG_CAR_AUDIO_FADE_MANAGER_CONFIGURATION);
6553          when(mMockResources.getBoolean(audioUseFadeManagerConfiguration)).thenReturn(true);
6554          return setUpAudioService();
6555      }
6556  
setUpCarAudioServiceUsingCoreAudioRoutingAndVolume()6557      private CarAudioService setUpCarAudioServiceUsingCoreAudioRoutingAndVolume() throws Exception {
6558          when(mMockResources.getBoolean(audioUseCoreVolume)).thenReturn(true);
6559          when(mMockResources.getBoolean(audioUseCoreRouting)).thenReturn(true);
6560          setUpTempFileForAudioConfiguration(
6561                  R.raw.car_audio_configuration_using_core_audio_routing_and_volume);
6562          setUpTempFileForAudioFadeConfiguration(R.raw.car_audio_fade_configuration);
6563  
6564          CarAudioService useCoreAudioCarAudioService = new CarAudioService(mMockContext,
6565                  mAudioManager,
6566                  mTempCarAudioConfigFile.getFile().getAbsolutePath(), mCarVolumeCallbackHandler,
6567                  /* audioFadeConfigurationPath= */ null);
6568          useCoreAudioCarAudioService.init();
6569          return useCoreAudioCarAudioService;
6570      }
6571  
mockGrantCarControlAudioSettingsPermission()6572      private void mockGrantCarControlAudioSettingsPermission() {
6573          mockContextCheckCallingOrSelfPermission(mMockContext,
6574                  PERMISSION_CAR_CONTROL_AUDIO_SETTINGS, PERMISSION_GRANTED);
6575      }
6576  
mockDenyCarControlAudioSettingsPermission()6577      private void mockDenyCarControlAudioSettingsPermission() {
6578          mockContextCheckCallingOrSelfPermission(mMockContext,
6579                  PERMISSION_CAR_CONTROL_AUDIO_SETTINGS, PERMISSION_DENIED);
6580      }
6581  
mockDenyCarControlAudioVolumePermission()6582      private void mockDenyCarControlAudioVolumePermission() {
6583          mockContextCheckCallingOrSelfPermission(mMockContext,
6584                  PERMISSION_CAR_CONTROL_AUDIO_VOLUME, PERMISSION_DENIED);
6585      }
6586  
generateInputDeviceInfos()6587      private AudioDeviceInfo[] generateInputDeviceInfos() {
6588          mMicrophoneInputDevice = new AudioDeviceInfoBuilder()
6589                  .setAddressName(PRIMARY_ZONE_MICROPHONE_ADDRESS)
6590                  .setType(TYPE_BUILTIN_MIC)
6591                  .setIsSource(true)
6592                  .build();
6593          mFmTunerInputDevice = new AudioDeviceInfoBuilder()
6594                  .setAddressName(PRIMARY_ZONE_FM_TUNER_ADDRESS)
6595                  .setType(TYPE_FM_TUNER)
6596                  .setIsSource(true)
6597                  .build();
6598          return new AudioDeviceInfo[]{mMicrophoneInputDevice, mFmTunerInputDevice};
6599      }
6600  
generateOutputDeviceInfos()6601      private AudioDeviceInfo[] generateOutputDeviceInfos() {
6602          mMediaOutputDevice = new AudioDeviceInfoBuilder()
6603                  .setAudioGains(new AudioGain[] {new GainBuilder().build()})
6604                  .setAddressName(MEDIA_TEST_DEVICE)
6605                  .build();
6606          mNotificationOutpuBus = new AudioDeviceInfoBuilder()
6607                  .setAudioGains(new AudioGain[] {new GainBuilder().build()})
6608                  .setAddressName(NOTIFICATION_TEST_DEVICE)
6609                  .build();
6610          mNavOutputDevice = new AudioDeviceInfoBuilder()
6611                  .setAudioGains(new AudioGain[] {new GainBuilder().build()})
6612                  .setAddressName(NAVIGATION_TEST_DEVICE)
6613                  .build();
6614          mVoiceOutpuBus = new AudioDeviceInfoBuilder()
6615                  .setAudioGains(new AudioGain[] {new GainBuilder().build()})
6616                  .setAddressName(VOICE_TEST_DEVICE)
6617                  .build();
6618          mSecondaryConfig0Group0Device = new AudioDeviceInfoBuilder()
6619                  .setAudioGains(new AudioGain[] {new GainBuilder().build()})
6620                  .setAddressName(SECONDARY_TEST_DEVICE_CONFIG_0)
6621                  .build();
6622          mSecondaryConfig1Group0Device = new AudioDeviceInfoBuilder()
6623                  .setAudioGains(new AudioGain[] {new GainBuilder().build()})
6624                  .setAddressName(SECONDARY_TEST_DEVICE_CONFIG_1_0)
6625                  .build();
6626          mSecondaryConfig1Group1Device = new AudioDeviceInfoBuilder()
6627                  .setAudioGains(new AudioGain[] {new GainBuilder().build()})
6628                  .setAddressName(SECONDARY_TEST_DEVICE_CONFIG_1_1)
6629                  .build();
6630          mBTAudioDeviceInfo = new AudioDeviceInfoBuilder()
6631                  .setAudioGains(new AudioGain[] {new GainBuilder().build()})
6632                  .setAddressName(TEST_BT_DEVICE)
6633                  .setType(TYPE_BLUETOOTH_A2DP)
6634                  .build();
6635          return new AudioDeviceInfo[] {
6636                  mBTAudioDeviceInfo,
6637                  mMediaOutputDevice,
6638                  mNavOutputDevice,
6639                  new AudioDeviceInfoBuilder()
6640                          .setAudioGains(new AudioGain[] {new GainBuilder().build()})
6641                          .setAddressName(CALL_TEST_DEVICE)
6642                          .build(),
6643                  new AudioDeviceInfoBuilder()
6644                          .setAudioGains(new AudioGain[] {new GainBuilder().build()})
6645                          .setAddressName(SYSTEM_BUS_DEVICE)
6646                          .build(),
6647                  mNotificationOutpuBus,
6648                  mVoiceOutpuBus,
6649                  new AudioDeviceInfoBuilder()
6650                          .setAudioGains(new AudioGain[] {new GainBuilder().build()})
6651                          .setAddressName(RING_TEST_DEVICE)
6652                          .build(),
6653                  new AudioDeviceInfoBuilder()
6654                          .setAudioGains(new AudioGain[] {new GainBuilder().build()})
6655                          .setAddressName(ALARM_TEST_DEVICE)
6656                          .build(),
6657                  new AudioDeviceInfoBuilder()
6658                          .setAudioGains(new AudioGain[] {new GainBuilder().build()})
6659                          .setAddressName(SECONDARY_TEST_DEVICE_CONFIG_0)
6660                          .build(),
6661                  mSecondaryConfig1Group0Device,
6662                  mSecondaryConfig1Group1Device,
6663                  new AudioDeviceInfoBuilder()
6664                          .setAudioGains(new AudioGain[] {new GainBuilder().build()})
6665                          .setAddressName(TERTIARY_TEST_DEVICE_1)
6666                          .build(),
6667                  new AudioDeviceInfoBuilder()
6668                          .setAudioGains(new AudioGain[] {new GainBuilder().build()})
6669                          .setAddressName(TERTIARY_TEST_DEVICE_2)
6670                          .build(),
6671                  new AudioDeviceInfoBuilder()
6672                          .setAudioGains(new AudioGain[] {new GainBuilder().build()})
6673                          .setAddressName(QUATERNARY_TEST_DEVICE_1)
6674                          .build(),
6675                  new AudioDeviceInfoBuilder()
6676                          .setAudioGains(new AudioGain[] {new GainBuilder().build()})
6677                          .setAddressName(OEM_TEST_DEVICE)
6678                          .build(),
6679                  new AudioDeviceInfoBuilder()
6680                          .setAudioGains(new AudioGain[] {new GainBuilder().build()})
6681                          .setAddressName(MIRROR_TEST_DEVICE).build(),
6682                  new AudioDeviceInfoBuilder()
6683                          .setAudioGains(new AudioGain[] {new GainBuilder().build()})
6684                          .setAddressName(TEST_REAR_ROW_3_DEVICE).build(),
6685          };
6686      }
6687  
mockCoreAudioRoutingAndVolume()6688      private void mockCoreAudioRoutingAndVolume() {
6689          doReturn(CoreAudioRoutingUtils.getProductStrategies())
6690                  .when(AudioManagerWrapper::getAudioProductStrategies);
6691          doReturn(CoreAudioRoutingUtils.getVolumeGroups())
6692                  .when(AudioManagerWrapper::getAudioVolumeGroups);
6693  
6694          when(mAudioManager.getMinVolumeIndexForAttributes(
6695                  eq(CoreAudioRoutingUtils.MUSIC_ATTRIBUTES)))
6696                  .thenReturn(CoreAudioRoutingUtils.MUSIC_MIN_INDEX);
6697          when(mAudioManager.getMaxVolumeIndexForAttributes(
6698                  eq(CoreAudioRoutingUtils.MUSIC_ATTRIBUTES)))
6699                  .thenReturn(CoreAudioRoutingUtils.MUSIC_MAX_INDEX);
6700          when(mAudioManager.getVolumeIndexForAttributes(eq(CoreAudioRoutingUtils.MUSIC_ATTRIBUTES)))
6701                  .thenReturn(CoreAudioRoutingUtils.MUSIC_AM_INIT_INDEX);
6702          when(mAudioManager.getLastAudibleVolumeForVolumeGroup(CoreAudioRoutingUtils.MUSIC_GROUP_ID))
6703                  .thenReturn(CoreAudioRoutingUtils.MUSIC_AM_INIT_INDEX);
6704          when(mAudioManager.isVolumeGroupMuted(CoreAudioRoutingUtils.MUSIC_GROUP_ID))
6705                  .thenReturn(false);
6706  
6707          when(mAudioManager.getMinVolumeIndexForAttributes(eq(CoreAudioRoutingUtils.NAV_ATTRIBUTES)))
6708                  .thenReturn(CoreAudioRoutingUtils.NAV_MIN_INDEX);
6709          when(mAudioManager.getMaxVolumeIndexForAttributes(eq(CoreAudioRoutingUtils.NAV_ATTRIBUTES)))
6710                  .thenReturn(CoreAudioRoutingUtils.NAV_MAX_INDEX);
6711          when(mAudioManager.isVolumeGroupMuted(CoreAudioRoutingUtils.NAV_GROUP_ID))
6712                  .thenReturn(false);
6713  
6714          when(mAudioManager.getMinVolumeIndexForAttributes(eq(CoreAudioRoutingUtils.OEM_ATTRIBUTES)))
6715                  .thenReturn(CoreAudioRoutingUtils.OEM_MIN_INDEX);
6716          when(mAudioManager.getMaxVolumeIndexForAttributes(eq(CoreAudioRoutingUtils.OEM_ATTRIBUTES)))
6717                  .thenReturn(CoreAudioRoutingUtils.OEM_MAX_INDEX);
6718          when(mAudioManager.isVolumeGroupMuted(CoreAudioRoutingUtils.OEM_GROUP_ID))
6719                  .thenReturn(false);
6720  
6721          doReturn(CoreAudioRoutingUtils.MUSIC_GROUP_ID)
6722                  .when(() -> CoreAudioHelper.getVolumeGroupIdForAudioAttributes(
6723                          CoreAudioRoutingUtils.MUSIC_ATTRIBUTES));
6724          doReturn(CoreAudioRoutingUtils.MUSIC_ATTRIBUTES)
6725                  .when(() -> CoreAudioHelper.selectAttributesForVolumeGroupName(
6726                          CoreAudioRoutingUtils.MUSIC_GROUP_NAME));
6727  
6728          doReturn(CoreAudioRoutingUtils.NAV_GROUP_ID)
6729                  .when(() -> CoreAudioHelper.getVolumeGroupIdForAudioAttributes(
6730                          CoreAudioRoutingUtils.NAV_ATTRIBUTES));
6731          doReturn(CoreAudioRoutingUtils.NAV_ATTRIBUTES)
6732                  .when(() -> CoreAudioHelper.selectAttributesForVolumeGroupName(
6733                          CoreAudioRoutingUtils.NAV_GROUP_NAME));
6734  
6735          doReturn(CoreAudioRoutingUtils.OEM_GROUP_ID)
6736                  .when(() -> CoreAudioHelper.getVolumeGroupIdForAudioAttributes(
6737                          CoreAudioRoutingUtils.OEM_ATTRIBUTES));
6738          doReturn(CoreAudioRoutingUtils.OEM_ATTRIBUTES)
6739                  .when(() -> CoreAudioHelper.selectAttributesForVolumeGroupName(
6740                          CoreAudioRoutingUtils.OEM_GROUP_NAME));
6741      }
6742  
createAudioFocusInfoForMedia()6743      private static AudioFocusInfo createAudioFocusInfoForMedia() {
6744          return createAudioFocusInfoForMedia(MEDIA_APP_UID);
6745      }
6746  
createAudioFocusInfoForMedia(int uid)6747      private static AudioFocusInfo createAudioFocusInfoForMedia(int uid) {
6748          AudioAttributes.Builder builder = new AudioAttributes.Builder();
6749          builder.setUsage(USAGE_MEDIA);
6750  
6751          return new AudioFocusInfo(builder.build(), uid, MEDIA_CLIENT_ID,
6752                  MEDIA_PACKAGE_NAME, AUDIOFOCUS_GAIN, AUDIOFOCUS_LOSS, MEDIA_EMPTY_FLAG, SDK_INT);
6753      }
6754  
getFocusChanges(AudioFocusInfo info)6755      private List<Integer> getFocusChanges(AudioFocusInfo info) {
6756          ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(Integer.class);
6757          verify(mAudioManager, atLeastOnce()).dispatchAudioFocusChange(eq(info), captor.capture(),
6758                  any());
6759          return captor.getAllValues();
6760      }
6761  
verifyMediaDuckingInfoInZone(ArgumentCaptor<List<CarDuckingInfo>> carDuckingInfosCaptor, int zoneId, String message)6762      private void verifyMediaDuckingInfoInZone(ArgumentCaptor<List<CarDuckingInfo>>
6763              carDuckingInfosCaptor, int zoneId, String message) {
6764          expectWithMessage("Zone size of notified ducking info " + message)
6765                  .that(carDuckingInfosCaptor.getValue().size()).isEqualTo(1);
6766          CarDuckingInfo duckingInfo = carDuckingInfosCaptor.getValue().get(0);
6767          expectWithMessage("Ducking info zone id " + message)
6768                  .that(duckingInfo.mZoneId).isEqualTo(zoneId);
6769          expectWithMessage("Audio attributes holding focus " + message)
6770                  .that(CarHalAudioUtils.metadataToAudioAttributes(duckingInfo
6771                          .mPlaybackMetaDataHoldingFocus))
6772                  .containsExactly(CarAudioContext.getAudioAttributeFromUsage(USAGE_MEDIA));
6773      }
6774  
getZoneConfigToSwitch(CarAudioService service, int zoneId)6775      private CarAudioZoneConfigInfo getZoneConfigToSwitch(CarAudioService service, int zoneId) {
6776          CarAudioZoneConfigInfo currentZoneConfigInfo =
6777                  service.getCurrentAudioZoneConfigInfo(zoneId);
6778          List<CarAudioZoneConfigInfo> zoneConfigInfos = service.getAudioZoneConfigInfos(zoneId);
6779  
6780          for (int index = 0; index < zoneConfigInfos.size(); index++) {
6781              if (currentZoneConfigInfo.equals(zoneConfigInfos.get(index))) {
6782                  continue;
6783              }
6784              return zoneConfigInfos.get(index);
6785          }
6786          return null;
6787      }
6788  
setVolumeForGroup(CarAudioService service, TestCarVolumeEventCallback volumeEventCallback, int zoneId, int groupId, int volumeIndex)6789      private void setVolumeForGroup(CarAudioService service,
6790                                     TestCarVolumeEventCallback volumeEventCallback,
6791                                     int zoneId, int groupId, int volumeIndex) throws Exception {
6792          service.setGroupVolume(zoneId, groupId, volumeIndex, TEST_FLAGS);
6793          resetVolumeCallbacks(volumeEventCallback);
6794      }
6795  
createActivePlayback(AudioPlaybackCallback callback, TestCarVolumeEventCallback volumeEventCallback, int playbackUsage, String deviceAddress, int playbackUid)6796      private void createActivePlayback(AudioPlaybackCallback callback,
6797                                        TestCarVolumeEventCallback volumeEventCallback,
6798                                        int playbackUsage, String deviceAddress, int playbackUid)
6799              throws Exception {
6800          callback.onPlaybackConfigChanged(List.of(new AudioPlaybackConfigurationBuilder()
6801                  .setUsage(playbackUsage).setDeviceAddress(deviceAddress)
6802                  .setClientUid(playbackUid).build()));
6803          resetVolumeCallbacks(volumeEventCallback);
6804      }
6805  
resetVolumeCallbacks(TestCarVolumeEventCallback volumeEventCallback)6806      private void resetVolumeCallbacks(TestCarVolumeEventCallback volumeEventCallback)
6807              throws Exception {
6808          volumeEventCallback.waitForCallback();
6809          volumeEventCallback.reset();
6810          reset(mCarVolumeCallbackHandler);
6811      }
6812  
6813      private static final class TestAudioZoneConfigurationsChangeCallback
6814              extends IAudioZoneConfigurationsChangeCallback.Stub {
6815  
6816          private List<CarAudioZoneConfigInfo> mInfos;
6817          private int mStatus = INVALID_STATUS;
6818  
6819          private CountDownLatch mStatusLatch = new CountDownLatch(1);
6820          @Override
onAudioZoneConfigurationsChanged(List<CarAudioZoneConfigInfo> configs, int status)6821          public void onAudioZoneConfigurationsChanged(List<CarAudioZoneConfigInfo> configs,
6822                  int status) {
6823              mInfos = configs;
6824              mStatus = status;
6825              mStatusLatch.countDown();
6826          }
6827  
waitForCallback()6828          private void waitForCallback() throws Exception {
6829              mStatusLatch.await(TEST_ZONE_CONFIG_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
6830          }
6831  
reset()6832          public void reset() {
6833              mInfos = null;
6834              mStatus = INVALID_STATUS;
6835              mStatusLatch = new CountDownLatch(1);
6836          }
6837      }
6838  
6839      private static final class TestPrimaryZoneMediaAudioRequestCallback extends
6840              IPrimaryZoneMediaAudioRequestCallback.Stub {
6841          private long mRequestId = INVALID_REQUEST_ID;
6842          private CarOccupantZoneManager.OccupantZoneInfo mInfo;
6843          private CountDownLatch mStatusLatch = new CountDownLatch(1);
6844          private int mStatus;
6845          private DeathRecipient mDeathRecipient;
6846  
6847          @Override
linkToDeath(@onNull DeathRecipient recipient, int flags)6848          public void linkToDeath(@NonNull DeathRecipient recipient, int flags) {
6849              mDeathRecipient = recipient;
6850              super.linkToDeath(recipient, flags);
6851          }
6852  
6853          @Override
onRequestMediaOnPrimaryZone(CarOccupantZoneManager.OccupantZoneInfo info, long requestId)6854          public void onRequestMediaOnPrimaryZone(CarOccupantZoneManager.OccupantZoneInfo info,
6855                  long requestId) {
6856              mInfo = info;
6857              mRequestId = requestId;
6858              mStatusLatch.countDown();
6859          }
6860  
6861          @Override
onMediaAudioRequestStatusChanged( @onNull CarOccupantZoneManager.OccupantZoneInfo info, long requestId, int status)6862          public void onMediaAudioRequestStatusChanged(
6863                  @NonNull CarOccupantZoneManager.OccupantZoneInfo info,
6864                  long requestId, int status) {
6865              mInfo = info;
6866              mRequestId = requestId;
6867              mStatus = status;
6868              mStatusLatch.countDown();
6869          }
6870  
waitForCallback()6871          private void waitForCallback() throws Exception {
6872              mStatusLatch.await(TEST_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
6873          }
6874  
reset()6875          public void reset() {
6876              mInfo = null;
6877              mRequestId = INVALID_REQUEST_ID;
6878              mStatus = INVALID_STATUS;
6879              mStatusLatch = new CountDownLatch(1);
6880          }
6881      }
6882  
6883      private static final class TestMediaRequestStatusCallback extends
6884              IMediaAudioRequestStatusCallback.Stub {
6885          private long mRequestId = INVALID_REQUEST_ID;
6886          private CarOccupantZoneManager.OccupantZoneInfo mInfo;
6887          private int mStatus;
6888          private CountDownLatch mStatusLatch = new CountDownLatch(1);
6889  
6890          @Override
onMediaAudioRequestStatusChanged( @onNull CarOccupantZoneManager.OccupantZoneInfo info, long requestId, @CarAudioManager.MediaAudioRequestStatus int status)6891          public void onMediaAudioRequestStatusChanged(
6892                  @NonNull CarOccupantZoneManager.OccupantZoneInfo info,
6893                  long requestId, @CarAudioManager.MediaAudioRequestStatus int status)
6894                  throws RemoteException {
6895              mInfo = info;
6896              mRequestId = requestId;
6897              mStatus = status;
6898              mStatusLatch.countDown();
6899          }
6900  
waitForCallback()6901          private void waitForCallback() throws Exception {
6902              mStatusLatch.await(TEST_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
6903          }
6904  
reset()6905          private void reset() {
6906              mInfo = null;
6907              mRequestId = INVALID_REQUEST_ID;
6908              mStatus = INVALID_STATUS;
6909              mStatusLatch = new CountDownLatch(1);
6910          }
6911      }
6912  
6913      private static final class TestAudioZonesMirrorStatusCallbackCallback extends
6914              IAudioZonesMirrorStatusCallback.Stub {
6915  
6916          private static final long TEST_CALLBACK_TIMEOUT_MS = 300;
6917  
6918          private List<int[]> mZoneIds = new ArrayList<>();
6919          private List<Integer> mStatus = new ArrayList<>();
6920          private int mNumberOfCalls = 0;
6921          private CountDownLatch mStatusLatch;
6922  
TestAudioZonesMirrorStatusCallbackCallback(int count)6923          private TestAudioZonesMirrorStatusCallbackCallback(int count) {
6924              mStatusLatch = new CountDownLatch(count);
6925          }
6926  
6927          @Override
onAudioZonesMirrorStatusChanged(int[] zoneIds, int status)6928          public void onAudioZonesMirrorStatusChanged(int[] zoneIds, int status) {
6929              mZoneIds.add(zoneIds);
6930              mStatus.add(status);
6931              mNumberOfCalls++;
6932              mStatusLatch.countDown();
6933          }
6934  
waitForCallback()6935          private void waitForCallback() throws Exception {
6936              mStatusLatch.await(TEST_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
6937          }
6938  
reset(int count)6939          public void reset(int count) {
6940              mStatusLatch = new CountDownLatch(count);
6941          }
6942  
getLastZoneIds()6943          private int[] getLastZoneIds() {
6944              return mZoneIds.get(mZoneIds.size() - 1);
6945          }
6946  
getLastStatus()6947          public int getLastStatus() {
6948              return mStatus.get(mStatus.size() - 1);
6949          }
6950      }
6951  
6952      private static final class SwitchAudioZoneConfigCallbackImpl extends
6953              ISwitchAudioZoneConfigCallback.Stub {
6954          private CountDownLatch mStatusLatch = new CountDownLatch(1);
6955          private CarAudioZoneConfigInfo mZoneConfig;
6956          private boolean mIsSuccessful;
6957  
6958          @Override
onAudioZoneConfigSwitched(CarAudioZoneConfigInfo zoneConfig, boolean isSuccessful)6959          public void onAudioZoneConfigSwitched(CarAudioZoneConfigInfo zoneConfig,
6960                  boolean isSuccessful) {
6961              mZoneConfig = zoneConfig;
6962              mIsSuccessful = isSuccessful;
6963              mStatusLatch.countDown();
6964          }
6965  
waitForCallback()6966          private void waitForCallback() throws Exception {
6967              mStatusLatch.await(TEST_ZONE_CONFIG_CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS);
6968          }
6969  
getZoneConfig()6970          CarAudioZoneConfigInfo getZoneConfig() {
6971              return mZoneConfig;
6972          }
6973  
getSwitchStatus()6974          boolean getSwitchStatus() {
6975              return mIsSuccessful;
6976          }
6977  
reset()6978          public void reset() {
6979              mZoneConfig = null;
6980              mIsSuccessful = false;
6981              mStatusLatch = new CountDownLatch(1);
6982          }
6983      }
6984  }
6985