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