CarAudioExtFocusTest.java revision 4c6834a27ccbcf42cbeef43059751752baf80ac3
1/*
2 * Copyright (C) 2016 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 */
16package com.android.car.test;
17
18import android.car.Car;
19import android.car.media.CarAudioManager;
20import android.car.test.VehicleHalEmulator.VehicleHalPropertyHandler;
21import android.content.Context;
22import android.media.AudioAttributes;
23import android.media.AudioManager;
24import android.os.SystemClock;
25import android.test.suitebuilder.annotation.MediumTest;
26import android.util.Log;
27
28import com.android.car.vehiclenetwork.VehicleNetworkConsts;
29import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioContextFlag;
30import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioExtFocusFlag;
31import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioFocusIndex;
32import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioFocusRequest;
33import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioFocusState;
34import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioStream;
35import com.android.car.vehiclenetwork.VehiclePropConfigUtil;
36import com.android.car.vehiclenetwork.VehiclePropValueUtil;
37import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehiclePermissionModel;
38import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehiclePropAccess;
39import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehiclePropChangeMode;
40import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleValueType;
41import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValue;
42
43import java.util.Arrays;
44import java.util.LinkedList;
45import java.util.concurrent.Semaphore;
46import java.util.concurrent.TimeUnit;
47
48@MediumTest
49public class CarAudioExtFocusTest extends MockedCarTestBase {
50    private static final String TAG = CarAudioExtFocusTest.class.getSimpleName();
51
52    private static final long TIMEOUT_MS = 3000;
53
54    private final VehicleHalPropertyHandler mAudioRoutingPolicyPropertyHandler =
55            new VehicleHalPropertyHandler() {
56        @Override
57        public void onPropertySet(VehiclePropValue value) {
58            //TODO
59        }
60
61        @Override
62        public VehiclePropValue onPropertyGet(VehiclePropValue value) {
63            fail("cannot get");
64            return null;
65        }
66
67        @Override
68        public void onPropertySubscribe(int property, float sampleRate, int zones) {
69            fail("cannot subscribe");
70        }
71
72        @Override
73        public void onPropertyUnsubscribe(int property) {
74            fail("cannot unsubscribe");
75        }
76    };
77
78    private final FocusPropertyHandler mAudioFocusPropertyHandler =
79            new FocusPropertyHandler(this);
80
81    private final ExtRoutingHintPropertyHandler mExtRoutingHintPropertyHandler =
82            new ExtRoutingHintPropertyHandler();
83
84    private static final String EXT_ROUTING_CONFIG =
85            "0:RADIO_AM_FM:0,1:RADIO_SATELLITE:0,33:CD_DVD:0," +
86            "64:com.google.test.SOMETHING_SPECIAL," +
87            "4:EXT_NAV_GUIDANCE:1," +
88            "5:AUX_IN0:0";
89
90    private final Semaphore mWaitSemaphore = new Semaphore(0);
91    private final LinkedList<VehiclePropValue> mEvents = new LinkedList<VehiclePropValue>();
92    private AudioManager mAudioManager;
93    private CarAudioManager mCarAudioManager;
94
95    @Override
96    protected void setUp() throws Exception {
97        super.setUp();
98        // AudioManager should be created in main thread to get focus event. :(
99        runOnMainSync(new Runnable() {
100            @Override
101            public void run() {
102                mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
103            }
104        });
105
106        getVehicleHalEmulator().addProperty(
107                VehiclePropConfigUtil.getBuilder(
108                        VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_ROUTING_POLICY,
109                        VehiclePropAccess.VEHICLE_PROP_ACCESS_WRITE,
110                        VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE,
111                        VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC2,
112                        VehiclePermissionModel.VEHICLE_PERMISSION_SYSTEM_APP_ONLY,
113                        0 /*configFlags*/, 0 /*sampleRateMax*/, 0 /*sampleRateMin*/).build(),
114                        mAudioRoutingPolicyPropertyHandler);
115        getVehicleHalEmulator().addProperty(
116                VehiclePropConfigUtil.getBuilder(
117                        VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_FOCUS,
118                        VehiclePropAccess.VEHICLE_PROP_ACCESS_READ_WRITE,
119                        VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE,
120                        VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC4,
121                        VehiclePermissionModel.VEHICLE_PERMISSION_SYSTEM_APP_ONLY,
122                        0 /*configFlags*/, 0 /*sampleRateMax*/, 0 /*sampleRateMin*/).build(),
123                        mAudioFocusPropertyHandler);
124        getVehicleHalEmulator().addStaticProperty(
125                VehiclePropConfigUtil.createStaticStringProperty(
126                        VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_HW_VARIANT),
127                VehiclePropValueUtil.createIntValue(
128                        VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_HW_VARIANT, 1, 0));
129        getVehicleHalEmulator().addProperty(
130                VehiclePropConfigUtil.getBuilder(
131                        VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_EXT_ROUTING_HINT,
132                        VehiclePropAccess.VEHICLE_PROP_ACCESS_WRITE,
133                        VehiclePropChangeMode.VEHICLE_PROP_CHANGE_MODE_ON_CHANGE,
134                        VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC4,
135                        VehiclePermissionModel.VEHICLE_PERMISSION_SYSTEM_APP_ONLY,
136                        0 /*configFlags*/, 0 /*sampleRateMax*/, 0 /*sampleRateMin*/).
137                        setConfigString(EXT_ROUTING_CONFIG).build(),
138                        mExtRoutingHintPropertyHandler);
139        getVehicleHalEmulator().start();
140        mCarAudioManager = (CarAudioManager) getCar().getCarManager(Car.AUDIO_SERVICE);
141        assertNotNull(mCarAudioManager);
142    }
143
144    public void testExtRoutings() throws Exception {
145        String[] radioTypes = mCarAudioManager.getSupportedRadioTypes();
146        assertNotNull(radioTypes);
147        checkStringArrayContents(new String[] {"RADIO_AM_FM", "RADIO_SATELLITE"}, radioTypes);
148
149        String[] nonRadioTypes = mCarAudioManager.getSupportedExternalSourceTypes();
150        assertNotNull(nonRadioTypes);
151        checkStringArrayContents(new String[] {"CD_DVD", "com.google.test.SOMETHING_SPECIAL",
152                "EXT_NAV_GUIDANCE", "AUX_IN0"}, nonRadioTypes);
153    }
154
155    private void checkStringArrayContents(String[] expected, String[] actual) throws Exception {
156        Arrays.sort(expected);
157        Arrays.sort(actual);
158        assertEquals(expected.length, actual.length);
159        for (int i = 0; i < expected.length; i++) {
160            assertEquals(expected[i], actual[i]);
161        }
162    }
163
164    public void testRadioAttributeCreation() throws Exception {
165        AudioAttributes attrb = mCarAudioManager.getAudioAttributesForRadio(
166                CarAudioManager.CAR_RADIO_TYPE_AM_FM);
167        assertNotNull(attrb);
168
169        attrb = mCarAudioManager.getAudioAttributesForRadio(
170                CarAudioManager.CAR_RADIO_TYPE_SATELLITE);
171        assertNotNull(attrb);
172
173        try {
174            attrb = mCarAudioManager.getAudioAttributesForRadio(
175                    CarAudioManager.CAR_RADIO_TYPE_AM_FM_HD);
176            fail();
177        } catch (IllegalArgumentException e) {
178            // expected
179        }
180    }
181
182    public void testExtSourceAttributeCreation() throws Exception {
183        AudioAttributes attrb = mCarAudioManager.getAudioAttributesForExternalSource(
184                CarAudioManager.CAR_EXTERNAL_SOURCE_TYPE_CD_DVD);
185        assertNotNull(attrb);
186
187        attrb = mCarAudioManager.getAudioAttributesForExternalSource(
188                CarAudioManager.CAR_EXTERNAL_SOURCE_TYPE_EXT_NAV_GUIDANCE);
189        assertNotNull(attrb);
190
191        attrb = mCarAudioManager.getAudioAttributesForExternalSource(
192                "com.google.test.SOMETHING_SPECIAL");
193        assertNotNull(attrb);
194
195        try {
196            attrb = mCarAudioManager.getAudioAttributesForExternalSource(
197                    CarAudioManager.CAR_RADIO_TYPE_AM_FM_HD);
198            fail();
199        } catch (IllegalArgumentException e) {
200            // expected
201        }
202    }
203
204    public void testRadioAmFmGainFocus() throws Exception {
205        AudioAttributes attrb = mCarAudioManager.getAudioAttributesForRadio(
206                CarAudioManager.CAR_RADIO_TYPE_AM_FM);
207        assertNotNull(attrb);
208        checkSingleRequestRelease(attrb, AudioManager.AUDIOFOCUS_GAIN, new int[] {1, 0, 0, 0},
209                0, VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG,
210                VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_RADIO_FLAG);
211    }
212
213    public void testRadioSatelliteGainFocus() throws Exception {
214        AudioAttributes attrb = mCarAudioManager.getAudioAttributesForRadio(
215                CarAudioManager.CAR_RADIO_TYPE_SATELLITE);
216        assertNotNull(attrb);
217        checkSingleRequestRelease(attrb, AudioManager.AUDIOFOCUS_GAIN, new int[] {2, 0, 0, 0},
218                0, VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG,
219                VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_RADIO_FLAG);
220    }
221
222    public void testCdGainFocus() throws Exception {
223        AudioAttributes attrb = mCarAudioManager.getAudioAttributesForExternalSource(
224                CarAudioManager.CAR_EXTERNAL_SOURCE_TYPE_CD_DVD);
225        assertNotNull(attrb);
226        checkSingleRequestRelease(attrb, AudioManager.AUDIOFOCUS_GAIN, new int[] {0, 2, 0, 0},
227                0, VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG,
228                VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_CD_ROM_FLAG);
229    }
230
231    public void testAuxInFocus() throws Exception {
232        AudioAttributes attrb = mCarAudioManager.getAudioAttributesForExternalSource(
233                CarAudioManager.CAR_EXTERNAL_SOURCE_TYPE_AUX_IN0);
234        assertNotNull(attrb);
235        checkSingleRequestRelease(attrb, AudioManager.AUDIOFOCUS_GAIN, new int[] {0x1<<5, 0, 0, 0},
236                0, VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG,
237                VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_AUX_AUDIO_FLAG);
238    }
239
240    public void testExtNavInFocus() throws Exception {
241        AudioAttributes attrb = mCarAudioManager.getAudioAttributesForExternalSource(
242                CarAudioManager.CAR_EXTERNAL_SOURCE_TYPE_EXT_NAV_GUIDANCE);
243        assertNotNull(attrb);
244        checkSingleRequestRelease(attrb, AudioManager.AUDIOFOCUS_GAIN, new int[] {0x1<<4, 0, 0, 0},
245                0, VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG,
246                VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_EXT_SOURCE_FLAG);
247    }
248
249    public void testCustomInFocus() throws Exception {
250        AudioAttributes attrb = mCarAudioManager.getAudioAttributesForExternalSource(
251                "com.google.test.SOMETHING_SPECIAL");
252        assertNotNull(attrb);
253        checkSingleRequestRelease(attrb, AudioManager.AUDIOFOCUS_GAIN, new int[] {0, 0, 1, 0},
254                0, VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG,
255                VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_EXT_SOURCE_FLAG);
256    }
257
258    public void testMediaNavFocus() throws Exception {
259        //music start
260        AudioFocusListener listenerMusic = new AudioFocusListener();
261        int res = mAudioManager.requestAudioFocus(listenerMusic,
262                AudioManager.STREAM_MUSIC,
263                AudioManager.AUDIOFOCUS_GAIN);
264        assertEquals(AudioManager.AUDIOFOCUS_REQUEST_GRANTED, res);
265        int[] request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
266        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN, request[0]);
267        assertEquals(0x1 << VehicleAudioStream.VEHICLE_AUDIO_STREAM0, request[1]);
268        assertEquals(0, request[2]);
269        assertEquals(VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_MUSIC_FLAG, request[3]);
270        assertArrayEquals(new int[] {0, 0, 0, 0},
271                mExtRoutingHintPropertyHandler.getLastHint());
272        mAudioFocusPropertyHandler.sendAudioFocusState(
273                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN,
274                request[1],
275                VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_NONE_FLAG);
276
277        // nav guidance start
278        AudioFocusListener listenerNav = new AudioFocusListener();
279        AudioAttributes navAttrib = (new AudioAttributes.Builder()).
280                setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION).
281                setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE).
282                build();
283        res = mAudioManager.requestAudioFocus(listenerNav, navAttrib,
284                AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, 0);
285        request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
286        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN, request[0]);
287        assertEquals(0x3, request[1]);
288        assertEquals(0, request[2]);
289        assertEquals(VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_MUSIC_FLAG |
290                VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_NAVIGATION_FLAG, request[3]);
291        assertArrayEquals(new int[] {0, 0, 0, 0},
292                mExtRoutingHintPropertyHandler.getLastHint());
293        mAudioFocusPropertyHandler.sendAudioFocusState(
294                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN, request[1],
295                VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_NONE_FLAG);
296
297        // nav guidance done
298        mAudioManager.abandonAudioFocus(listenerNav);
299        request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
300        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN, request[0]);
301        assertEquals(0x1 << VehicleAudioStream.VEHICLE_AUDIO_STREAM0, request[1]);
302        assertEquals(0, request[2]);
303        assertEquals(VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_MUSIC_FLAG, request[3]);
304        assertArrayEquals(new int[] {0, 0, 0, 0},
305                mExtRoutingHintPropertyHandler.getLastHint());
306        mAudioFocusPropertyHandler.sendAudioFocusState(
307                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN, request[1],
308                VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_NONE_FLAG);
309
310        // music done
311        mAudioManager.abandonAudioFocus(listenerMusic);
312        request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
313        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_RELEASE, request[0]);
314        assertEquals(0, request[1]);
315        assertEquals(0, request[2]);
316        assertEquals(0, request[3]);
317        assertArrayEquals(new int[] {0, 0, 0, 0},
318                mExtRoutingHintPropertyHandler.getLastHint());
319        mAudioFocusPropertyHandler.sendAudioFocusState(
320                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS, request[1],
321                VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_NONE_FLAG);
322    }
323
324    public void testMediaExternalMediaNavFocus() throws Exception {
325        // android music
326        AudioFocusListener listenerMusic = new AudioFocusListener();
327        int res = mAudioManager.requestAudioFocus(listenerMusic,
328                AudioManager.STREAM_MUSIC,
329                AudioManager.AUDIOFOCUS_GAIN);
330        assertEquals(AudioManager.AUDIOFOCUS_REQUEST_GRANTED, res);
331        int[] request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
332        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN, request[0]);
333        assertEquals(0x1 << VehicleAudioStream.VEHICLE_AUDIO_STREAM0, request[1]);
334        assertEquals(0, request[2]);
335        assertEquals(VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_MUSIC_FLAG, request[3]);
336        assertArrayEquals(new int[] {0, 0, 0, 0},
337                mExtRoutingHintPropertyHandler.getLastHint());
338        mAudioFocusPropertyHandler.sendAudioFocusState(
339                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN,
340                request[1],
341                VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_NONE_FLAG);
342
343        // car plays external media (=outside Android)
344        mAudioFocusPropertyHandler.sendAudioFocusState(
345                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS,
346                0,
347                VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PERMANENT_FLAG);
348        int focusChange = listenerMusic.waitAndGetFocusChange(TIMEOUT_MS);
349        assertEquals(AudioManager.AUDIOFOCUS_LOSS, focusChange);
350
351        // nav guidance start
352        AudioFocusListener listenerNav = new AudioFocusListener();
353        AudioAttributes navAttrib = (new AudioAttributes.Builder()).
354                setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION).
355                setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE).
356                build();
357        res = mAudioManager.requestAudioFocus(listenerNav, navAttrib,
358                AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, 0);
359        request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
360        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT_MAY_DUCK,
361                request[0]);
362        assertEquals(0x1 << VehicleAudioStream.VEHICLE_AUDIO_STREAM1, request[1]);
363        assertEquals(0, request[2]);
364        assertEquals(VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_NAVIGATION_FLAG, request[3]);
365        assertArrayEquals(new int[] {0, 0, 0, 0},
366                mExtRoutingHintPropertyHandler.getLastHint());
367        mAudioFocusPropertyHandler.sendAudioFocusState(
368                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN_TRANSIENT,
369                0x1 << VehicleAudioStream.VEHICLE_AUDIO_STREAM1,
370                VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PERMANENT_FLAG);
371
372        // nav guidance ends
373        mAudioManager.abandonAudioFocus(listenerNav);
374        request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
375        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_RELEASE, request[0]);
376        assertEquals(0, request[1]);
377        assertEquals(0, request[2]);
378        assertEquals(0, request[3]);
379        assertArrayEquals(new int[] {0, 0, 0, 0},
380                mExtRoutingHintPropertyHandler.getLastHint());
381        mAudioFocusPropertyHandler.sendAudioFocusState(
382                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS,
383                0,
384                VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PERMANENT_FLAG);
385
386        // now ends external play
387        mAudioFocusPropertyHandler.sendAudioFocusState(
388                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS,
389                0,
390                0);
391        mAudioManager.abandonAudioFocus(listenerMusic);
392        //TODO how to check this?
393    }
394
395    public void testExternalRadioExternalNav() throws Exception {
396        // android radio
397        AudioFocusListener listenerRadio = new AudioFocusListener();
398        CarAudioManager carAudioManager = (CarAudioManager) getCar().getCarManager(
399                Car.AUDIO_SERVICE);
400        assertNotNull(carAudioManager);
401        AudioAttributes radioAttributes = carAudioManager.getAudioAttributesForCarUsage(
402                CarAudioManager.CAR_AUDIO_USAGE_RADIO);
403        int res = mAudioManager.requestAudioFocus(listenerRadio,
404                radioAttributes, AudioManager.AUDIOFOCUS_GAIN, 0);
405        assertEquals(AudioManager.AUDIOFOCUS_REQUEST_GRANTED, res);
406        int[] request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
407        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN, request[0]);
408        assertEquals(0, request[1]);
409        assertEquals(VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG,
410                request[2]);
411        assertEquals(VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_RADIO_FLAG, request[3]);
412        assertArrayEquals(new int[] {1, 0, 0, 0},
413                mExtRoutingHintPropertyHandler.getLastHint());
414        mAudioFocusPropertyHandler.sendAudioFocusState(
415                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN,
416                0,
417                VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG);
418
419        //external nav
420        AudioFocusListener listenerNav = new AudioFocusListener();
421        AudioAttributes extNavAttributes = mCarAudioManager.getAudioAttributesForExternalSource(
422                CarAudioManager.CAR_EXTERNAL_SOURCE_TYPE_EXT_NAV_GUIDANCE);
423        res = mAudioManager.requestAudioFocus(listenerNav,
424                extNavAttributes, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, 0);
425        assertEquals(AudioManager.AUDIOFOCUS_REQUEST_GRANTED, res);
426        request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
427        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN,
428                request[0]);
429        assertEquals(0, request[1]);
430        assertEquals(VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG,
431                request[2]);
432        assertEquals(VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_RADIO_FLAG |
433                VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_EXT_SOURCE_FLAG, request[3]);
434        assertArrayEquals(new int[] {1 | 1<<4, 0, 0, 0},
435                mExtRoutingHintPropertyHandler.getLastHint());
436        mAudioFocusPropertyHandler.sendAudioFocusState(
437                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN,
438                0,
439                VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG);
440
441        mAudioManager.abandonAudioFocus(listenerNav);
442        request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
443        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN, request[0]);
444        assertEquals(0, request[1]);
445        assertEquals(VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG,
446                request[2]);
447        assertEquals(VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_RADIO_FLAG, request[3]);
448        assertArrayEquals(new int[] {1, 0, 0, 0},
449                mExtRoutingHintPropertyHandler.getLastHint());
450        mAudioFocusPropertyHandler.sendAudioFocusState(
451                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN,
452                0,
453                VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG);
454
455        mAudioManager.abandonAudioFocus(listenerRadio);
456        request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
457        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_RELEASE, request[0]);
458        assertEquals(0, request[1]);
459        assertEquals(0, request[2]);
460        assertEquals(0, request[3]);
461        assertArrayEquals(new int[] {0, 0, 0, 0},
462                mExtRoutingHintPropertyHandler.getLastHint());
463        mAudioFocusPropertyHandler.sendAudioFocusState(
464                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS,
465                0,
466                0);
467    }
468
469    public void testMediaExternalNav() throws Exception {
470        // android music
471        AudioFocusListener listenerMusic = new AudioFocusListener();
472        int res = mAudioManager.requestAudioFocus(listenerMusic,
473                AudioManager.STREAM_MUSIC,
474                AudioManager.AUDIOFOCUS_GAIN);
475        assertEquals(AudioManager.AUDIOFOCUS_REQUEST_GRANTED, res);
476        int[] request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
477        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN, request[0]);
478        assertEquals(0x1 << VehicleAudioStream.VEHICLE_AUDIO_STREAM0, request[1]);
479        assertEquals(0, request[2]);
480        assertEquals(VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_MUSIC_FLAG, request[3]);
481        assertArrayEquals(new int[] {0, 0, 0, 0},
482                mExtRoutingHintPropertyHandler.getLastHint());
483        mAudioFocusPropertyHandler.sendAudioFocusState(
484                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN,
485                request[1],
486                VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_NONE_FLAG);
487
488        //external nav
489        AudioFocusListener listenerNav = new AudioFocusListener();
490        AudioAttributes extNavAttributes = mCarAudioManager.getAudioAttributesForExternalSource(
491                CarAudioManager.CAR_EXTERNAL_SOURCE_TYPE_EXT_NAV_GUIDANCE);
492        res = mAudioManager.requestAudioFocus(listenerNav,
493                extNavAttributes, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, 0);
494        assertEquals(AudioManager.AUDIOFOCUS_REQUEST_GRANTED, res);
495        request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
496        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN,
497                request[0]);
498        assertEquals(0x1, request[1]);
499        assertEquals(VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG,
500                request[2]);
501        assertEquals(VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_MUSIC_FLAG |
502                VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_EXT_SOURCE_FLAG, request[3]);
503        assertArrayEquals(new int[] {1<<4, 0, 0, 0},
504                mExtRoutingHintPropertyHandler.getLastHint());
505        mAudioFocusPropertyHandler.sendAudioFocusState(
506                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN,
507                0x1,
508                VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG);
509
510        mAudioManager.abandonAudioFocus(listenerNav);
511        request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
512        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN, request[0]);
513        assertEquals(0x1 << VehicleAudioStream.VEHICLE_AUDIO_STREAM0, request[1]);
514        assertEquals(0, request[2]);
515        assertEquals(VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_MUSIC_FLAG, request[3]);
516        assertArrayEquals(new int[] {0, 0, 0, 0},
517                mExtRoutingHintPropertyHandler.getLastHint());
518        mAudioFocusPropertyHandler.sendAudioFocusState(
519                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN,
520                request[1],
521                VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_NONE_FLAG);
522
523        mAudioManager.abandonAudioFocus(listenerMusic);
524        request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
525        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_RELEASE, request[0]);
526        assertEquals(0, request[1]);
527        assertEquals(0, request[2]);
528        assertEquals(0, request[3]);
529        assertArrayEquals(new int[] {0, 0, 0, 0},
530                mExtRoutingHintPropertyHandler.getLastHint());
531        mAudioFocusPropertyHandler.sendAudioFocusState(
532                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS,
533                0,
534                0);
535    }
536
537    /**
538     * Test internal nav - external nav case.
539     * External nav takes the same physical stream as internal nav. So internal nav
540     * will be lost while external nav is played. This should not happen in real case when
541     * AppFocus is used, but this test is to make sure that audio focus works as expected.
542     */
543    public void testNavExternalNav() throws Exception {
544        // android nav
545        AudioFocusListener listenerIntNav = new AudioFocusListener();
546        AudioAttributes intNavAttributes = mCarAudioManager.getAudioAttributesForCarUsage(
547                CarAudioManager.CAR_AUDIO_USAGE_NAVIGATION_GUIDANCE);
548        int res = mAudioManager.requestAudioFocus(listenerIntNav, intNavAttributes,
549                AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, 0);
550        assertEquals(AudioManager.AUDIOFOCUS_REQUEST_GRANTED, res);
551        int[] request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
552        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT_MAY_DUCK,
553                request[0]);
554        assertEquals(0x2, request[1]);
555        assertEquals(0, request[2]);
556        assertEquals(VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_NAVIGATION_FLAG, request[3]);
557        assertArrayEquals(new int[] {0, 0, 0, 0},
558                mExtRoutingHintPropertyHandler.getLastHint());
559        mAudioFocusPropertyHandler.sendAudioFocusState(
560                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN,
561                request[1],
562                VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_NONE_FLAG);
563
564        //external nav
565        AudioFocusListener listenerExtNav = new AudioFocusListener();
566        AudioAttributes extNavAttributes = mCarAudioManager.getAudioAttributesForExternalSource(
567                CarAudioManager.CAR_EXTERNAL_SOURCE_TYPE_EXT_NAV_GUIDANCE);
568        res = mAudioManager.requestAudioFocus(listenerExtNav,
569                extNavAttributes, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, 0);
570        assertEquals(AudioManager.AUDIOFOCUS_REQUEST_GRANTED, res);
571        request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
572        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN,
573                request[0]);
574        assertEquals(0, request[1]);
575        assertEquals(VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG,
576                request[2]);
577        assertEquals(VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_EXT_SOURCE_FLAG, request[3]);
578        assertArrayEquals(new int[] {1<<4, 0, 0, 0},
579                mExtRoutingHintPropertyHandler.getLastHint());
580        mAudioFocusPropertyHandler.sendAudioFocusState(
581                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN,
582                0x1,
583                VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG);
584
585        mAudioManager.abandonAudioFocus(listenerExtNav);
586        request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
587        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT_MAY_DUCK,
588                request[0]);
589        assertEquals(0x2, request[1]);
590        assertEquals(0, request[2]);
591        assertEquals(VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_NAVIGATION_FLAG, request[3]);
592        assertArrayEquals(new int[] {0, 0, 0, 0},
593                mExtRoutingHintPropertyHandler.getLastHint());
594        mAudioFocusPropertyHandler.sendAudioFocusState(
595                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN,
596                request[1],
597                VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_NONE_FLAG);
598
599        mAudioManager.abandonAudioFocus(listenerIntNav);
600        request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
601        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_RELEASE, request[0]);
602        assertEquals(0, request[1]);
603        assertEquals(0, request[2]);
604        assertEquals(0, request[3]);
605        assertArrayEquals(new int[] {0, 0, 0, 0},
606                mExtRoutingHintPropertyHandler.getLastHint());
607        mAudioFocusPropertyHandler.sendAudioFocusState(
608                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS,
609                0,
610                0);
611    }
612
613    public void testMediaExternalRadioNavMediaFocus() throws Exception {
614        // android music
615        AudioFocusListener listenerMusic = new AudioFocusListener();
616        int res = mAudioManager.requestAudioFocus(listenerMusic,
617                AudioManager.STREAM_MUSIC,
618                AudioManager.AUDIOFOCUS_GAIN);
619        assertEquals(AudioManager.AUDIOFOCUS_REQUEST_GRANTED, res);
620        int[] request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
621        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN, request[0]);
622        assertEquals(0x1 << VehicleAudioStream.VEHICLE_AUDIO_STREAM0, request[1]);
623        assertEquals(0, request[2]);
624        assertEquals(VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_MUSIC_FLAG, request[3]);
625        assertArrayEquals(new int[] {0, 0, 0, 0},
626                mExtRoutingHintPropertyHandler.getLastHint());
627        mAudioFocusPropertyHandler.sendAudioFocusState(
628                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN,
629                request[1],
630                VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_NONE_FLAG);
631
632        // android radio
633        AudioFocusListener listenerRadio = new AudioFocusListener();
634        CarAudioManager carAudioManager = (CarAudioManager) getCar().getCarManager(
635                Car.AUDIO_SERVICE);
636        assertNotNull(carAudioManager);
637        AudioAttributes radioAttributes = carAudioManager.getAudioAttributesForCarUsage(
638                CarAudioManager.CAR_AUDIO_USAGE_RADIO);
639        res = mAudioManager.requestAudioFocus(listenerRadio,
640                radioAttributes, AudioManager.AUDIOFOCUS_GAIN, 0);
641        assertEquals(AudioManager.AUDIOFOCUS_REQUEST_GRANTED, res);
642        request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
643        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN, request[0]);
644        assertEquals(0, request[1]);
645        assertEquals(VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG,
646                request[2]);
647        assertEquals(VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_RADIO_FLAG, request[3]);
648        assertArrayEquals(new int[] {1, 0, 0, 0},
649                mExtRoutingHintPropertyHandler.getLastHint());
650        mAudioFocusPropertyHandler.sendAudioFocusState(
651                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN,
652                0,
653                VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG);
654
655        // nav guidance start
656        AudioFocusListener listenerNav = new AudioFocusListener();
657        AudioAttributes navAttrib = (new AudioAttributes.Builder()).
658                setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION).
659                setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE).
660                build();
661        res = mAudioManager.requestAudioFocus(listenerNav, navAttrib,
662                AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, 0);
663        request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
664        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN,
665                request[0]);
666        assertEquals(0x1 << VehicleAudioStream.VEHICLE_AUDIO_STREAM1, request[1]);
667        assertEquals(VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG,
668                request[2]);
669        assertEquals(VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_NAVIGATION_FLAG |
670                VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_RADIO_FLAG, request[3]);
671        assertArrayEquals(new int[] {1, 0, 0, 0},
672                mExtRoutingHintPropertyHandler.getLastHint());
673        mAudioFocusPropertyHandler.sendAudioFocusState(
674                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN,
675                0x1 << VehicleAudioStream.VEHICLE_AUDIO_STREAM1,
676                VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG);
677
678        // nav guidance ends
679        mAudioManager.abandonAudioFocus(listenerNav);
680        request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
681        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN,
682                request[0]);
683        assertEquals(0, request[1]);
684        assertEquals(VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG,
685                request[2]);
686        assertEquals(VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_RADIO_FLAG, request[3]);
687        assertArrayEquals(new int[] {1, 0, 0, 0},
688                mExtRoutingHintPropertyHandler.getLastHint());
689        mAudioFocusPropertyHandler.sendAudioFocusState(
690                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN,
691                0,
692                VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG);
693
694        // ends radio. music will get the focus GAIN.
695        // Music app is supposed to stop and release focus when it has lost focus, but here just
696        // check if focus is working.
697        mAudioManager.abandonAudioFocus(listenerRadio);
698        listenerMusic.waitForFocus(TIMEOUT_MS, AudioManager.AUDIOFOCUS_GAIN);
699        request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
700        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN, request[0]);
701        assertEquals(0x1 << VehicleAudioStream.VEHICLE_AUDIO_STREAM0, request[1]);
702        assertEquals(0, request[2]);
703        assertEquals(VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_MUSIC_FLAG, request[3]);
704        assertArrayEquals(new int[] {0, 0, 0, 0},
705                mExtRoutingHintPropertyHandler.getLastHint());
706        mAudioFocusPropertyHandler.sendAudioFocusState(
707                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN,
708                0x1 << VehicleAudioStream.VEHICLE_AUDIO_STREAM0,
709                0);
710
711        // now music release focus.
712        mAudioManager.abandonAudioFocus(listenerMusic);
713        request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
714        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_RELEASE, request[0]);
715        assertEquals(0, request[1]);
716        assertEquals(0, request[2]);
717        assertEquals(0, request[3]);
718        assertArrayEquals(new int[] {0, 0, 0, 0},
719                mExtRoutingHintPropertyHandler.getLastHint());
720        mAudioFocusPropertyHandler.sendAudioFocusState(
721                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS,
722                0,
723                VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_NONE_FLAG);
724    }
725
726    private void checkSingleRequestRelease(AudioAttributes attrb, int androidFocusToRequest,
727            int[] expectedExtRouting, int expectedStreams,
728            int expectedExtState, int expectedContexts) throws Exception {
729        AudioFocusListener lister = new AudioFocusListener();
730        int res = mCarAudioManager.requestAudioFocus(lister, attrb, androidFocusToRequest, 0);
731        assertEquals(AudioManager.AUDIOFOCUS_REQUEST_GRANTED, res);
732        int[] request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
733        int expectedFocusRequest = VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_RELEASE;
734        int response = VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS;
735        switch (androidFocusToRequest) {
736            case AudioManager.AUDIOFOCUS_GAIN:
737                expectedFocusRequest = VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN;
738                response = VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN;
739                break;
740            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT:
741                expectedFocusRequest =
742                    VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT;
743                response = VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN_TRANSIENT;
744                break;
745            case AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
746                expectedFocusRequest =
747                    VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT_MAY_DUCK;
748                response = VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN_TRANSIENT;
749                break;
750        }
751        assertEquals(expectedFocusRequest, request[0]);
752        assertEquals(expectedStreams, request[1]);
753        assertEquals(expectedExtState, request[2]);
754        assertEquals(expectedContexts, request[3]);
755        assertArrayEquals(expectedExtRouting, mExtRoutingHintPropertyHandler.getLastHint());
756        mAudioFocusPropertyHandler.sendAudioFocusState(
757                response,
758                request[1],
759                VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_NONE_FLAG);
760        mAudioManager.abandonAudioFocus(lister);
761        request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
762        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_RELEASE, request[0]);
763        assertEquals(0, request[1]);
764        assertEquals(0, request[2]);
765        assertEquals(0, request[3]);
766        assertArrayEquals(new int[] {0, 0, 0, 0},
767                mExtRoutingHintPropertyHandler.getLastHint());
768        mAudioFocusPropertyHandler.sendAudioFocusState(
769                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS,
770                request[1],
771                VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_NONE_FLAG);
772    }
773
774    public void testRadioMute() throws Exception {
775        testMediaMute(CarAudioManager.CAR_AUDIO_USAGE_RADIO,
776                0,
777                VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG,
778                VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_RADIO_FLAG);
779    }
780
781    public void testMusicMute() throws Exception {
782        testMediaMute(CarAudioManager.CAR_AUDIO_USAGE_MUSIC,
783                0x1,
784                0,
785                VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_MUSIC_FLAG);
786    }
787
788    private void testMediaMute(int mediaUsage, int primaryStream, int extFocusFlag,
789            int mediaContext) throws Exception {
790        // android radio
791        AudioFocusListener listenerMedia = new AudioFocusListener();
792        CarAudioManager carAudioManager = (CarAudioManager) getCar().getCarManager(
793                Car.AUDIO_SERVICE);
794        assertNotNull(carAudioManager);
795        AudioAttributes radioAttributes = carAudioManager.getAudioAttributesForCarUsage(mediaUsage);
796        Log.i(TAG, "request media Focus");
797        int res = mAudioManager.requestAudioFocus(listenerMedia,
798                radioAttributes, AudioManager.AUDIOFOCUS_GAIN, 0);
799        assertEquals(AudioManager.AUDIOFOCUS_REQUEST_GRANTED, res);
800        int[] request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
801        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN, request[0]);
802        assertEquals(primaryStream, request[1]);
803        assertEquals(extFocusFlag, request[2]);
804        assertEquals(mediaContext, request[3]);
805        if (mediaUsage == CarAudioManager.CAR_AUDIO_USAGE_RADIO) {
806            assertArrayEquals(new int[] {1, 0, 0, 0},
807                    mExtRoutingHintPropertyHandler.getLastHint());
808        } else {
809            assertArrayEquals(new int[] {0, 0, 0, 0},
810                    mExtRoutingHintPropertyHandler.getLastHint());
811        }
812        mAudioFocusPropertyHandler.sendAudioFocusState(
813                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN,
814                primaryStream,
815                extFocusFlag);
816        // now mute it.
817        assertFalse(carAudioManager.isMediaMuted());
818        Log.i(TAG, "mute media");
819        assertTrue(carAudioManager.setMediaMute(true));
820        request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
821        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT,
822                request[0]);
823        assertEquals(0, request[1]);
824        assertEquals(VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_MUTE_MEDIA_FLAG,
825                request[2]);
826        assertEquals(0, request[3]);
827        assertArrayEquals(new int[] {0, 0, 0, 0},
828                mExtRoutingHintPropertyHandler.getLastHint());
829        mAudioFocusPropertyHandler.sendAudioFocusState(
830                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN,
831                0,
832                VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_MUTE_MEDIA_FLAG);
833        assertTrue(carAudioManager.isMediaMuted());
834        // nav guidance on top of it
835        AudioFocusListener listenerNav = new AudioFocusListener();
836        AudioAttributes navAttrib = (new AudioAttributes.Builder()).
837                setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION).
838                setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE).
839                build();
840        Log.i(TAG, "request nav Focus");
841        res = mAudioManager.requestAudioFocus(listenerNav, navAttrib,
842                AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, 0);
843        request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
844        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT_MAY_DUCK,
845                request[0]);
846        assertEquals(0x1 << VehicleAudioStream.VEHICLE_AUDIO_STREAM1, request[1]);
847        assertEquals(VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_MUTE_MEDIA_FLAG,
848                request[2]);
849        assertEquals(VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_NAVIGATION_FLAG, request[3]);
850        assertArrayEquals(new int[] {0, 0, 0, 0},
851                mExtRoutingHintPropertyHandler.getLastHint());
852        assertTrue(carAudioManager.isMediaMuted());
853        mAudioFocusPropertyHandler.sendAudioFocusState(
854                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN,
855                0x1 << VehicleAudioStream.VEHICLE_AUDIO_STREAM1,
856                VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_MUTE_MEDIA_FLAG);
857        assertTrue(carAudioManager.isMediaMuted());
858        // nav guidance ends
859        mAudioManager.abandonAudioFocus(listenerNav);
860        request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
861        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT,
862                request[0]);
863        assertEquals(0, request[1]);
864        assertEquals(VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_MUTE_MEDIA_FLAG,
865                request[2]);
866        assertEquals(0, request[3]);
867        assertArrayEquals(new int[] {0, 0, 0, 0},
868                mExtRoutingHintPropertyHandler.getLastHint());
869        assertTrue(carAudioManager.isMediaMuted());
870        mAudioFocusPropertyHandler.sendAudioFocusState(
871                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN,
872                0,
873                VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_MUTE_MEDIA_FLAG);
874        // now unmute it. media should resume.
875        assertTrue(carAudioManager.isMediaMuted());
876        assertFalse(carAudioManager.setMediaMute(false));
877        assertFalse(carAudioManager.isMediaMuted());
878        request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
879        assertEquals(VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN, request[0]);
880        assertEquals(primaryStream, request[1]);
881        assertEquals(extFocusFlag,
882                request[2]);
883        assertEquals(mediaContext, request[3]);
884        if (mediaUsage == CarAudioManager.CAR_AUDIO_USAGE_RADIO) {
885            assertArrayEquals(new int[] {1, 0, 0, 0},
886                    mExtRoutingHintPropertyHandler.getLastHint());
887        } else {
888            assertArrayEquals(new int[] {0, 0, 0, 0},
889                    mExtRoutingHintPropertyHandler.getLastHint());
890        }
891        assertFalse(carAudioManager.isMediaMuted());
892        mAudioFocusPropertyHandler.sendAudioFocusState(
893                VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN,
894                primaryStream,
895                extFocusFlag);
896        assertFalse(carAudioManager.isMediaMuted());
897        // release focus
898        mAudioManager.abandonAudioFocus(listenerMedia);
899    }
900
901    protected static class AudioFocusListener implements AudioManager.OnAudioFocusChangeListener {
902        private final Semaphore mFocusChangeWait = new Semaphore(0);
903        private int mLastFocusChange;
904
905        public int waitAndGetFocusChange(long timeoutMs) throws Exception {
906            if (!mFocusChangeWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
907                fail("timeout waiting for focus change");
908            }
909            return mLastFocusChange;
910        }
911
912        public void waitForFocus(long timeoutMs, int expectedFocus) throws Exception {
913            while (mLastFocusChange != expectedFocus) {
914                if (!mFocusChangeWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
915                    fail("timeout waiting for focus change");
916                }
917            }
918        }
919
920        @Override
921        public void onAudioFocusChange(int focusChange) {
922            mLastFocusChange = focusChange;
923            mFocusChangeWait.release();
924        }
925    }
926
927    protected static class FocusPropertyHandler implements VehicleHalPropertyHandler {
928
929        private int mState = VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS;
930        private int mStreams = 0;
931        private int mExtFocus = 0;
932        private int mRequest;
933        private int mRequestedStreams;
934        private int mRequestedExtFocus;
935        private int mRequestedAudioContexts;
936        private final MockedCarTestBase mCarTest;
937
938        private final Semaphore mSetWaitSemaphore = new Semaphore(0);
939
940        public FocusPropertyHandler(MockedCarTestBase carTest) {
941            mCarTest = carTest;
942        }
943
944        public void sendAudioFocusState(int state, int streams, int extFocus) {
945            synchronized (this) {
946                mState = state;
947                mStreams = streams;
948                mExtFocus = extFocus;
949            }
950            int[] values = { state, streams, extFocus, 0 };
951            mCarTest.getVehicleHalEmulator().injectEvent(VehiclePropValueUtil.createIntVectorValue(
952                    VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_FOCUS, values,
953                    SystemClock.elapsedRealtimeNanos()));
954        }
955
956        public int[] waitForAudioFocusRequest(long timeoutMs) throws Exception {
957            if (!mSetWaitSemaphore.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
958                fail("timeout");
959            }
960            synchronized (this) {
961                return new int[] { mRequest, mRequestedStreams, mRequestedExtFocus,
962                        mRequestedAudioContexts };
963            }
964        }
965
966        @Override
967        public void onPropertySet(VehiclePropValue value) {
968            assertEquals(VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_FOCUS, value.getProp());
969            synchronized (this) {
970                mRequest = value.getInt32Values(
971                        VehicleAudioFocusIndex.VEHICLE_AUDIO_FOCUS_INDEX_FOCUS);
972                mRequestedStreams = value.getInt32Values(
973                        VehicleAudioFocusIndex.VEHICLE_AUDIO_FOCUS_INDEX_STREAMS);
974                mRequestedExtFocus = value.getInt32Values(
975                        VehicleAudioFocusIndex.VEHICLE_AUDIO_FOCUS_INDEX_EXTERNAL_FOCUS_STATE);
976                mRequestedAudioContexts = value.getInt32Values(
977                        VehicleAudioFocusIndex.VEHICLE_AUDIO_FOCUS_INDEX_AUDIO_CONTEXTS);
978            }
979            mSetWaitSemaphore.release();
980        }
981
982        @Override
983        public VehiclePropValue onPropertyGet(VehiclePropValue value) {
984            assertEquals(VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_FOCUS, value.getProp());
985            int state, streams, extFocus;
986            synchronized (this) {
987                state = mState;
988                streams = mStreams;
989                extFocus = mExtFocus;
990            }
991            int[] values = { state, streams, extFocus, 0 };
992            return VehiclePropValueUtil.createIntVectorValue(
993                    VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_FOCUS, values,
994                    SystemClock.elapsedRealtimeNanos());
995        }
996
997        @Override
998        public void onPropertySubscribe(int property, float sampleRate, int zones) {
999            assertEquals(VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_FOCUS, property);
1000        }
1001
1002        @Override
1003        public void onPropertyUnsubscribe(int property) {
1004            assertEquals(VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_FOCUS, property);
1005        }
1006    }
1007
1008    private static class ExtRoutingHintPropertyHandler implements VehicleHalPropertyHandler {
1009        private int[] mLastHint = {0, 0, 0, 0};
1010
1011        public int[] getLastHint() {
1012            int[] lastHint = new int[mLastHint.length];
1013            synchronized (this) {
1014                System.arraycopy(mLastHint, 0, lastHint, 0, mLastHint.length);
1015            }
1016            return lastHint;
1017        }
1018
1019        @Override
1020        public void onPropertySet(VehiclePropValue value) {
1021            assertEquals(VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_EXT_ROUTING_HINT,
1022                    value.getProp());
1023            assertEquals(mLastHint.length, value.getInt32ValuesCount());
1024            synchronized (this) {
1025                for (int i = 0; i < mLastHint.length; i++) {
1026                    mLastHint[i] = value.getInt32Values(i);
1027                }
1028            }
1029        }
1030
1031        @Override
1032        public VehiclePropValue onPropertyGet(VehiclePropValue value) {
1033            fail("write only");
1034            return null;
1035        }
1036
1037        @Override
1038        public void onPropertySubscribe(int property, float sampleRate, int zones) {
1039            fail("cannot subsctibe");
1040        }
1041
1042        @Override
1043        public void onPropertyUnsubscribe(int property) {
1044            fail("cannot subsctibe");
1045        }
1046    }
1047}
1048