• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.media.AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
20 import static android.media.AudioAttributes.USAGE_MEDIA;
21 import static android.media.AudioAttributes.USAGE_VOICE_COMMUNICATION;
22 import static android.media.AudioManager.AUDIOFOCUS_GAIN;
23 import static android.media.AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
24 import static android.media.AudioManager.AUDIOFOCUS_REQUEST_DELAYED;
25 import static android.media.AudioManager.AUDIOFOCUS_REQUEST_FAILED;
26 import static android.media.AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
27 
28 import static com.google.common.truth.Truth.assertThat;
29 
30 import static org.mockito.ArgumentMatchers.anyInt;
31 import static org.mockito.ArgumentMatchers.eq;
32 import static org.mockito.Mockito.never;
33 import static org.mockito.Mockito.verify;
34 import static org.mockito.Mockito.when;
35 
36 import android.car.media.CarAudioManager;
37 import android.content.ContentResolver;
38 import android.content.pm.PackageManager;
39 import android.media.AudioAttributes;
40 import android.media.AudioFocusInfo;
41 import android.media.AudioManager;
42 import android.media.audiopolicy.AudioPolicy;
43 import android.os.Build;
44 import android.os.Bundle;
45 import android.util.SparseArray;
46 
47 import com.android.car.audio.CarZonesAudioFocus.CarFocusCallback;
48 
49 import org.junit.Before;
50 import org.junit.Test;
51 import org.junit.runner.RunWith;
52 import org.mockito.ArgumentCaptor;
53 import org.mockito.Mock;
54 import org.mockito.junit.MockitoJUnitRunner;
55 
56 import java.util.List;
57 
58 @RunWith(MockitoJUnitRunner.class)
59 public class CarZonesAudioFocusTest {
60     private static final String MEDIA_CLIENT_ID = "media-client-id";
61     private static final String NAVIGATION_CLIENT_ID = "nav-client-id";
62     private static final String CALL_CLIENT_ID = "call-client-id";
63     private static final String PACKAGE_NAME = "com.android.car.audio";
64     private static final int AUDIOFOCUS_FLAG = 0;
65     private static final int PRIMARY_ZONE_ID = CarAudioManager.PRIMARY_AUDIO_ZONE;
66     private static final int SECONDARY_ZONE_ID = CarAudioManager.PRIMARY_AUDIO_ZONE + 1;
67     private static final int MEDIA_CLIENT_UID_1 = 1086753;
68     private static final int MEDIA_CLIENT_UID_2 = 1000009;
69     private static final int NAVIGATION_CLIENT_UID = 1010101;
70     private static final int TEST_USER_ID = 10;
71     private static final int CALL_CLIENT_UID = 1086753;
72 
73     @Mock
74     private AudioManager mMockAudioManager;
75     @Mock
76     private AudioPolicy mAudioPolicy;
77     @Mock
78     private CarAudioService mCarAudioService;
79     @Mock
80     private ContentResolver mContentResolver;
81     @Mock
82     private CarAudioSettings mCarAudioSettings;
83     @Mock
84     private CarFocusCallback mMockCarFocusCallback;
85     @Mock
86     private PackageManager mMockPackageManager;
87 
88     private SparseArray<CarAudioZone> mCarAudioZones;
89 
90     @Before
setUp()91     public void setUp() {
92         mCarAudioZones = generateAudioZones();
93         when(mCarAudioService.getZoneIdForUid(MEDIA_CLIENT_UID_1)).thenReturn(PRIMARY_ZONE_ID);
94     }
95 
96     @Test
onAudioFocusRequest_withNoCurrentFocusHolder_requestGranted()97     public void onAudioFocusRequest_withNoCurrentFocusHolder_requestGranted() {
98         CarZonesAudioFocus carZonesAudioFocus = getCarZonesAudioFocus(false);
99         AudioFocusInfo audioFocusInfo = generateMediaRequestForPrimaryZone();
100 
101         requestFocusAndAssertIfRequestNotGranted(carZonesAudioFocus, audioFocusInfo);
102 
103         verify(mMockAudioManager, never())
104                 .dispatchAudioFocusChange(eq(audioFocusInfo), anyInt(), eq(mAudioPolicy));
105     }
106 
107     @Test
onAudioFocusRequest_forTwoDifferentZones_requestGranted()108     public void onAudioFocusRequest_forTwoDifferentZones_requestGranted() {
109         CarZonesAudioFocus carZonesAudioFocus = getCarZonesAudioFocus(false);
110         AudioFocusInfo audioFocusInfoClient1 = generateMediaRequestForPrimaryZone();
111 
112 
113         requestFocusAndAssertIfRequestNotGranted(carZonesAudioFocus, audioFocusInfoClient1);
114 
115         when(mCarAudioService.getZoneIdForUid(MEDIA_CLIENT_UID_2)).thenReturn(SECONDARY_ZONE_ID);
116         AudioFocusInfo audioFocusInfoClient2 = new AudioFocusInfoBuilder().setUsage(USAGE_MEDIA)
117                 .setClientId(MEDIA_CLIENT_ID).setGainRequest(AUDIOFOCUS_GAIN)
118                 .setClientUid(MEDIA_CLIENT_UID_2).createAudioFocusInfo();
119 
120         requestFocusAndAssertIfRequestNotGranted(carZonesAudioFocus, audioFocusInfoClient2);
121 
122         verify(mMockAudioManager, never())
123                 .dispatchAudioFocusChange(eq(audioFocusInfoClient1), anyInt(), eq(mAudioPolicy));
124 
125         verify(mMockAudioManager, never())
126                 .dispatchAudioFocusChange(eq(audioFocusInfoClient2), anyInt(), eq(mAudioPolicy));
127     }
128 
129     @Test
onAudioFocusRequest_forTwoDifferentZones_abandonInOne_requestGranted()130     public void onAudioFocusRequest_forTwoDifferentZones_abandonInOne_requestGranted() {
131         CarZonesAudioFocus carZonesAudioFocus = getCarZonesAudioFocus(false);
132         AudioFocusInfo audioFocusInfoClient1 = generateMediaRequestForPrimaryZone();
133 
134         requestFocusAndAssertIfRequestNotGranted(carZonesAudioFocus, audioFocusInfoClient1);
135 
136         when(mCarAudioService.getZoneIdForUid(MEDIA_CLIENT_UID_2)).thenReturn(SECONDARY_ZONE_ID);
137         AudioFocusInfo audioFocusInfoClient2 = new AudioFocusInfoBuilder().setUsage(USAGE_MEDIA)
138                 .setClientId(MEDIA_CLIENT_ID).setGainRequest(AUDIOFOCUS_GAIN)
139                 .setClientUid(MEDIA_CLIENT_UID_2).createAudioFocusInfo();
140 
141         requestFocusAndAssertIfRequestNotGranted(carZonesAudioFocus, audioFocusInfoClient2);
142 
143         carZonesAudioFocus.onAudioFocusAbandon(audioFocusInfoClient2);
144 
145         verify(mMockAudioManager, never())
146                 .dispatchAudioFocusChange(eq(audioFocusInfoClient1), anyInt(), eq(mAudioPolicy));
147 
148         verify(mMockAudioManager, never())
149                 .dispatchAudioFocusChange(eq(audioFocusInfoClient2), anyInt(), eq(mAudioPolicy));
150     }
151 
152     @Test
onAudioFocusRequest_withBundleFocusRequest_requestGranted()153     public void onAudioFocusRequest_withBundleFocusRequest_requestGranted() {
154         CarZonesAudioFocus carZonesAudioFocus = getCarZonesAudioFocus(false);
155         when(mCarAudioService.isAudioZoneIdValid(PRIMARY_ZONE_ID)).thenReturn(true);
156 
157         Bundle bundle = new Bundle();
158         bundle.putInt(CarAudioManager.AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID,
159                 PRIMARY_ZONE_ID);
160         AudioFocusInfo audioFocusInfoClient = new AudioFocusInfoBuilder().setUsage(USAGE_MEDIA)
161                 .setClientId(MEDIA_CLIENT_ID).setGainRequest(AUDIOFOCUS_GAIN)
162                 .setClientUid(MEDIA_CLIENT_UID_1).setBundle(bundle).createAudioFocusInfo();
163 
164         requestFocusAndAssertIfRequestNotGranted(carZonesAudioFocus, audioFocusInfoClient);
165 
166         verify(mMockAudioManager, never())
167                 .dispatchAudioFocusChange(eq(audioFocusInfoClient), anyInt(), eq(mAudioPolicy));
168     }
169 
170     @Test
onAudioFocusRequest_repeatForSameZone_requestGranted()171     public void onAudioFocusRequest_repeatForSameZone_requestGranted() {
172         CarZonesAudioFocus carZonesAudioFocus = getCarZonesAudioFocus(false);
173         AudioFocusInfo audioFocusInfoMediaClient = generateMediaRequestForPrimaryZone();
174 
175         requestFocusAndAssertIfRequestNotGranted(carZonesAudioFocus, audioFocusInfoMediaClient);
176 
177         when(mCarAudioService.getZoneIdForUid(NAVIGATION_CLIENT_UID)).thenReturn(PRIMARY_ZONE_ID);
178         AudioFocusInfo audioFocusInfoNavClient =
179                 new AudioFocusInfoBuilder().setUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
180                         .setClientId(NAVIGATION_CLIENT_ID).setGainRequest(AUDIOFOCUS_GAIN)
181                         .setClientUid(NAVIGATION_CLIENT_UID).createAudioFocusInfo();
182 
183         requestFocusAndAssertIfRequestNotGranted(carZonesAudioFocus, audioFocusInfoNavClient);
184 
185         verify(mMockAudioManager)
186                 .dispatchAudioFocusChange(eq(audioFocusInfoMediaClient),
187                         anyInt(), eq(mAudioPolicy));
188 
189         verify(mMockAudioManager, never())
190                 .dispatchAudioFocusChange(eq(audioFocusInfoNavClient),
191                         anyInt(), eq(mAudioPolicy));
192     }
193 
194     @Test
onAudioFocusRequest_forNavigationWhileOnCall_rejectNavOnCall_requestFailed()195     public void onAudioFocusRequest_forNavigationWhileOnCall_rejectNavOnCall_requestFailed() {
196         CarZonesAudioFocus carZonesAudioFocus = getCarZonesAudioFocus(false);
197         when(mCarAudioService.isAudioZoneIdValid(PRIMARY_ZONE_ID)).thenReturn(true);
198         setUpRejectNavigationOnCallValue(true);
199         carZonesAudioFocus.updateUserForZoneId(PRIMARY_ZONE_ID, TEST_USER_ID);
200 
201         when(mCarAudioService.getZoneIdForUid(CALL_CLIENT_UID)).thenReturn(PRIMARY_ZONE_ID);
202         AudioFocusInfo audioFocusInfoCallClient = new AudioFocusInfoBuilder()
203                 .setUsage(USAGE_VOICE_COMMUNICATION)
204                 .setGainRequest(AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK)
205                 .setClientId(CALL_CLIENT_ID)
206                 .setClientUid(CALL_CLIENT_UID).createAudioFocusInfo();
207 
208         requestFocusAndAssertIfRequestNotGranted(carZonesAudioFocus, audioFocusInfoCallClient);
209 
210         when(mCarAudioService.getZoneIdForUid(NAVIGATION_CLIENT_UID)).thenReturn(PRIMARY_ZONE_ID);
211         AudioFocusInfo audioFocusInfoNavClient =
212                 new AudioFocusInfoBuilder().setUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
213                         .setGainRequest(AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK)
214                         .setClientId(NAVIGATION_CLIENT_ID)
215                         .setClientUid(NAVIGATION_CLIENT_UID).createAudioFocusInfo();
216 
217         carZonesAudioFocus
218                 .onAudioFocusRequest(audioFocusInfoNavClient, AUDIOFOCUS_REQUEST_GRANTED);
219         verify(mMockAudioManager).setFocusRequestResult(audioFocusInfoNavClient,
220                 AUDIOFOCUS_REQUEST_FAILED, mAudioPolicy);
221     }
222 
223     @Test
onAudioFocusRequest_forNavigationWhileOnCall_noRejectNavOnCall_requestSucceeds()224     public void onAudioFocusRequest_forNavigationWhileOnCall_noRejectNavOnCall_requestSucceeds() {
225         CarZonesAudioFocus carZonesAudioFocus = getCarZonesAudioFocus(false);
226         when(mCarAudioService.isAudioZoneIdValid(PRIMARY_ZONE_ID)).thenReturn(true);
227         setUpRejectNavigationOnCallValue(false);
228         carZonesAudioFocus.updateUserForZoneId(PRIMARY_ZONE_ID, TEST_USER_ID);
229 
230         when(mCarAudioService.getZoneIdForUid(CALL_CLIENT_UID)).thenReturn(PRIMARY_ZONE_ID);
231         AudioFocusInfo audioFocusInfoCallClient = new AudioFocusInfoBuilder()
232                 .setUsage(USAGE_VOICE_COMMUNICATION)
233                 .setGainRequest(AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK)
234                 .setClientId(CALL_CLIENT_ID)
235                 .setClientUid(CALL_CLIENT_UID).createAudioFocusInfo();
236 
237         requestFocusAndAssertIfRequestNotGranted(carZonesAudioFocus, audioFocusInfoCallClient);
238 
239         when(mCarAudioService.getZoneIdForUid(NAVIGATION_CLIENT_UID)).thenReturn(PRIMARY_ZONE_ID);
240         AudioFocusInfo audioFocusInfoNavClient =
241                 new AudioFocusInfoBuilder().setUsage(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
242                         .setGainRequest(AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK)
243                         .setClientId(NAVIGATION_CLIENT_ID)
244                         .setClientUid(NAVIGATION_CLIENT_UID).createAudioFocusInfo();
245 
246 
247         carZonesAudioFocus
248                 .onAudioFocusRequest(audioFocusInfoNavClient, AUDIOFOCUS_REQUEST_GRANTED);
249         verify(mMockAudioManager).setFocusRequestResult(audioFocusInfoNavClient,
250                 AUDIOFOCUS_REQUEST_GRANTED, mAudioPolicy);
251     }
252 
253     @Test
onAudioFocusRequest_forMediaWhileOnCall_withDelayedEnable_delayedSucceeds()254     public void onAudioFocusRequest_forMediaWhileOnCall_withDelayedEnable_delayedSucceeds() {
255         CarZonesAudioFocus carZonesAudioFocus = getCarZonesAudioFocus(true);
256         when(mCarAudioService.isAudioZoneIdValid(PRIMARY_ZONE_ID)).thenReturn(true);
257 
258         when(mCarAudioService.getZoneIdForUid(CALL_CLIENT_UID)).thenReturn(PRIMARY_ZONE_ID);
259         AudioFocusInfo audioFocusInfoCallClient = new AudioFocusInfoBuilder()
260                 .setUsage(USAGE_VOICE_COMMUNICATION)
261                 .setGainRequest(AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK)
262                 .setClientId(CALL_CLIENT_ID)
263                 .setClientUid(CALL_CLIENT_UID).createAudioFocusInfo();
264 
265         requestFocusAndAssertIfRequestNotGranted(carZonesAudioFocus, audioFocusInfoCallClient);
266 
267         AudioFocusInfo audioFocusMediaClient =
268                 new AudioFocusInfoBuilder().setUsage(USAGE_MEDIA)
269                         .setGainRequest(AUDIOFOCUS_GAIN)
270                         .setClientId(MEDIA_CLIENT_ID)
271                         .setDelayedFocusRequestEnable(true)
272                         .setClientUid(MEDIA_CLIENT_UID_1).createAudioFocusInfo();
273 
274 
275         carZonesAudioFocus
276                 .onAudioFocusRequest(audioFocusMediaClient, AUDIOFOCUS_REQUEST_GRANTED);
277         verify(mMockAudioManager).setFocusRequestResult(audioFocusMediaClient,
278                 AUDIOFOCUS_REQUEST_DELAYED, mAudioPolicy);
279     }
280 
281     @Test
onAudioFocusRequest_notifiesFocusCallback()282     public void onAudioFocusRequest_notifiesFocusCallback() {
283         CarZonesAudioFocus carZonesAudioFocus = getCarZonesAudioFocus(true);
284         AudioFocusInfo audioFocusInfo = generateMediaRequestForPrimaryZone();
285 
286         carZonesAudioFocus.onAudioFocusRequest(audioFocusInfo, AUDIOFOCUS_REQUEST_GRANTED);
287 
288         ArgumentCaptor<SparseArray<List<AudioFocusInfo>>> focusHoldersCaptor =
289                 ArgumentCaptor.forClass(SparseArray.class);
290         verify(mMockCarFocusCallback).onFocusChange(eq(new int[]{PRIMARY_ZONE_ID}),
291                 focusHoldersCaptor.capture());
292         assertThat(focusHoldersCaptor.getValue().get(PRIMARY_ZONE_ID))
293                 .containsExactly(audioFocusInfo);
294     }
295 
296     @Test
onAudioFocusAbandon_notifiesFocusCallback()297     public void onAudioFocusAbandon_notifiesFocusCallback() {
298         CarZonesAudioFocus carZonesAudioFocus = getCarZonesAudioFocus(true);
299         AudioFocusInfo audioFocusInfo = generateMediaRequestForPrimaryZone();
300 
301         carZonesAudioFocus.onAudioFocusAbandon(audioFocusInfo);
302 
303         ArgumentCaptor<SparseArray<List<AudioFocusInfo>>> focusHoldersCaptor =
304                 ArgumentCaptor.forClass(SparseArray.class);
305         verify(mMockCarFocusCallback).onFocusChange(eq(new int[]{PRIMARY_ZONE_ID}),
306                 focusHoldersCaptor.capture());
307         assertThat(focusHoldersCaptor.getValue().get(PRIMARY_ZONE_ID)).isEmpty();
308     }
309 
generateMediaRequestForPrimaryZone()310     private AudioFocusInfo generateMediaRequestForPrimaryZone() {
311         return new AudioFocusInfoBuilder().setUsage(USAGE_MEDIA)
312                 .setClientId(MEDIA_CLIENT_ID).setGainRequest(AUDIOFOCUS_GAIN)
313                 .setClientUid(MEDIA_CLIENT_UID_1).createAudioFocusInfo();
314     }
315 
requestFocusAndAssertIfRequestNotGranted(CarZonesAudioFocus carZonesAudioFocus, AudioFocusInfo audioFocusClient)316     private void requestFocusAndAssertIfRequestNotGranted(CarZonesAudioFocus carZonesAudioFocus,
317             AudioFocusInfo audioFocusClient) {
318         requestFocusAndAssertIfRequestDiffers(carZonesAudioFocus, audioFocusClient,
319                 AUDIOFOCUS_REQUEST_GRANTED);
320     }
321 
requestFocusAndAssertIfRequestDiffers(CarZonesAudioFocus carZonesAudioFocus, AudioFocusInfo audioFocusClient, int expectedAudioFocusResults)322     private void requestFocusAndAssertIfRequestDiffers(CarZonesAudioFocus carZonesAudioFocus,
323             AudioFocusInfo audioFocusClient, int expectedAudioFocusResults) {
324         carZonesAudioFocus.onAudioFocusRequest(audioFocusClient, expectedAudioFocusResults);
325         verify(mMockAudioManager)
326                 .setFocusRequestResult(audioFocusClient, expectedAudioFocusResults, mAudioPolicy);
327     }
328 
generateAudioZones()329     private SparseArray<CarAudioZone> generateAudioZones() {
330         SparseArray<CarAudioZone> zones = new SparseArray<>();
331         zones.put(PRIMARY_ZONE_ID, new CarAudioZone(PRIMARY_ZONE_ID, "Primary zone"));
332         zones.put(SECONDARY_ZONE_ID, new CarAudioZone(SECONDARY_ZONE_ID, "Secondary zone"));
333         return zones;
334     }
335 
getCarZonesAudioFocus(boolean enableDelayedFocus)336     private CarZonesAudioFocus getCarZonesAudioFocus(boolean enableDelayedFocus) {
337         CarZonesAudioFocus carZonesAudioFocus =
338                 CarZonesAudioFocus.createCarZonesAudioFocus(mMockAudioManager, mMockPackageManager,
339                         mCarAudioZones,
340                         mCarAudioSettings, enableDelayedFocus, mMockCarFocusCallback);
341         carZonesAudioFocus.setOwningPolicy(mCarAudioService, mAudioPolicy);
342 
343 
344         return carZonesAudioFocus;
345     }
346 
setUpRejectNavigationOnCallValue(boolean rejectNavigationOnCall)347     private void setUpRejectNavigationOnCallValue(boolean rejectNavigationOnCall) {
348         when(mCarAudioSettings.getContentResolver()).thenReturn(mContentResolver);
349         when(mCarAudioSettings.isRejectNavigationOnCallEnabledInSettings(TEST_USER_ID))
350                 .thenReturn(rejectNavigationOnCall);
351     }
352 
353     public class AudioFocusInfoBuilder {
354         private int mUsage;
355         private int mClientUid;
356         private String mClientId;
357         private int mGainRequest;
358         private String mPackageName = PACKAGE_NAME;
359         private Bundle mBundle = null;
360         private int mLossReceived = AudioManager.AUDIOFOCUS_NONE;
361         private int mFlags = AUDIOFOCUS_FLAG;
362         private int mSdk = Build.VERSION.SDK_INT;
363         private boolean mDelayedFocusRequestEnabled = false;
364 
setUsage(int usage)365         public AudioFocusInfoBuilder setUsage(int usage) {
366             mUsage = usage;
367             return this;
368         }
369 
setClientUid(int clientUid)370         public AudioFocusInfoBuilder setClientUid(int clientUid) {
371             mClientUid = clientUid;
372             return this;
373         }
374 
setClientId(String clientId)375         public AudioFocusInfoBuilder setClientId(String clientId) {
376             mClientId = clientId;
377             return this;
378         }
379 
setPackageName(String packageName)380         public AudioFocusInfoBuilder setPackageName(String packageName) {
381             mPackageName = packageName;
382             return this;
383         }
384 
setGainRequest(int gainRequest)385         public AudioFocusInfoBuilder setGainRequest(int gainRequest) {
386             mGainRequest = gainRequest;
387             return this;
388         }
389 
setLossReceived(int lossReceived)390         public AudioFocusInfoBuilder setLossReceived(int lossReceived) {
391             mLossReceived = lossReceived;
392             return this;
393         }
394 
setSdk(int sdk)395         public AudioFocusInfoBuilder setSdk(int sdk) {
396             mSdk = sdk;
397             return this;
398         }
399 
setBundle(Bundle bundle)400         public AudioFocusInfoBuilder setBundle(Bundle bundle) {
401             mBundle = bundle;
402             return this;
403         }
404 
setDelayedFocusRequestEnable(boolean b)405         public AudioFocusInfoBuilder setDelayedFocusRequestEnable(boolean b) {
406             mDelayedFocusRequestEnabled = b;
407             return this;
408         }
409 
createAudioFocusInfo()410         public AudioFocusInfo createAudioFocusInfo() {
411             AudioAttributes.Builder builder = new AudioAttributes.Builder().setUsage(mUsage);
412             if (mBundle != null) {
413                 builder = builder.addBundle(mBundle);
414             }
415             if (mDelayedFocusRequestEnabled) {
416                 mFlags = mFlags | AudioManager.AUDIOFOCUS_FLAG_DELAY_OK;
417             }
418             AudioAttributes audioAttributes = builder.build();
419             return new AudioFocusInfo(audioAttributes, mClientUid, mClientId,
420                     mPackageName, mGainRequest, mLossReceived, mFlags, mSdk);
421         }
422     }
423 }
424