1fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park/*
2fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park * Copyright (C) 2017 The Android Open Source Project
3fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park *
4fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park * Licensed under the Apache License, Version 2.0 (the "License");
5fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park * you may not use this file except in compliance with the License.
6fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park * You may obtain a copy of the License at
7fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park *
8fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park *      http://www.apache.org/licenses/LICENSE-2.0
9fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park *
10fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park * Unless required by applicable law or agreed to in writing, software
11fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park * distributed under the License is distributed on an "AS IS" BASIS,
12fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park * See the License for the specific language governing permissions and
14fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park * limitations under the License.
15fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park */
16fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Parkpackage com.android.car.test;
17fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
18fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Parkimport android.car.Car;
19fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Parkimport android.car.media.CarAudioManager;
20cfe93105f637c2822da113308f113ed418d0b319Pavel Maltsevimport android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
21cfe93105f637c2822da113308f113ed418d0b319Pavel Maltsevimport android.hardware.automotive.vehicle.V2_0.VehicleProperty;
22cfe93105f637c2822da113308f113ed418d0b319Pavel Maltsevimport android.hardware.automotive.vehicle.V2_0.VehiclePropertyAccess;
23fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Parkimport android.os.SystemClock;
24fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Parkimport android.test.suitebuilder.annotation.MediumTest;
25fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
26fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Parkimport com.android.car.vehiclehal.VehiclePropValueBuilder;
27fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Parkimport com.android.car.vehiclehal.test.MockedVehicleHal.VehicleHalPropertyHandler;
28fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
29fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Parkimport java.util.concurrent.Semaphore;
30fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Parkimport java.util.concurrent.TimeUnit;
31fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
32fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park@MediumTest
33fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Parkpublic class CarAudioManagerTest extends MockedCarTestBase {
34fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park    private final AudioParametersPropertyHandler mAudioParametersPropertyHandler =
35fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            new AudioParametersPropertyHandler();
36fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park    CarAudioManager mCarAudioManager;
37fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
38fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park    @Override
39fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park    protected synchronized void configureMockedHal() {
40fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        addProperty(VehicleProperty.AUDIO_PARAMETERS, mAudioParametersPropertyHandler)
41fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park	    .setAccess(VehiclePropertyAccess.READ_WRITE)
42fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park	    .setConfigString("com.android.test.param1;com.android.test.param2");
43fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park    }
44fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
45fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park    @Override
46fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park    protected void setUp() throws Exception {
47fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        super.setUp();
48fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        mCarAudioManager = (CarAudioManager) getCar().getCarManager(
49fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park                Car.AUDIO_SERVICE);
50fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        assertNotNull(mCarAudioManager);
51fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park    }
52fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
53fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park    public void testAudioParamConfig() throws Exception {
54fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        String[] keys = mCarAudioManager.getParameterKeys();
55fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        assertNotNull(keys);
56fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        assertEquals(2, keys.length);
57fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        assertEquals("com.android.test.param1", keys[0]);
58fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        assertEquals("com.android.test.param2", keys[1]);
59fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park    }
60fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
61fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park    public void testAudioParamSet() throws Exception {
62fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        try {
63fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            mCarAudioManager.setParameters(null);
64fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            fail();
65fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        } catch (IllegalArgumentException e) {
66fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            // expected
67fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        }
68fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
69fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        try {
70fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            mCarAudioManager.setParameters("com.android.test.param3=3");
71fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            fail();
72fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        } catch (IllegalArgumentException e) {
73fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            // expected
74fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        }
75fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
76fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        final String SET_OK1 = "com.android.test.param1=1";
77fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        mCarAudioManager.setParameters(SET_OK1);
78fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        mAudioParametersPropertyHandler.waitForSet(DEFAULT_WAIT_TIMEOUT_MS, SET_OK1);
79fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
80fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        final String SET_OK2 = "com.android.test.param1=1;com.android.test.param2=2";
81fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        mCarAudioManager.setParameters(SET_OK2);
82fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        mAudioParametersPropertyHandler.waitForSet(DEFAULT_WAIT_TIMEOUT_MS, SET_OK2);
83fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park    }
84fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
85fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park    public void testAudioParamGet() throws Exception {
86fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        try {
87fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            mCarAudioManager.getParameters(null);
88fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            fail();
89fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        } catch (IllegalArgumentException e) {
90fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            // expected
91fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        }
92fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
93fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        try {
94fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            mCarAudioManager.getParameters("com.android.test.param3");
95fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            fail();
96fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        } catch (IllegalArgumentException e) {
97fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            // expected
98fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        }
99fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
100fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        try {
101fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            mCarAudioManager.getParameters("com.android.test.param1;com.android.test.param3");
102fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            fail();
103fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        } catch (IllegalArgumentException e) {
104fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            // expected
105fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        }
106fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
107fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        final String GET_RESP1 = "com.android.test.param1=1";
108fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        mAudioParametersPropertyHandler.setValueForGet(GET_RESP1);
109fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        String get1 = mCarAudioManager.getParameters("com.android.test.param1");
110fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        assertEquals(GET_RESP1, get1);
111fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
112fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        final String GET_RESP2 = "com.android.test.param1=1;com.android.test.param2=2";
113fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        mAudioParametersPropertyHandler.setValueForGet(GET_RESP2);
114fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        String get2 = mCarAudioManager.getParameters(
115fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park                "com.android.test.param1;com.android.test.param2");
116fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        assertEquals(GET_RESP2, get2);
117fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park    }
118fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
119fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park    public void testAudioParamChangeListener() throws Exception {
120fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        AudioParamListener listener1 = new AudioParamListener();
121fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        AudioParamListener listener2 = new AudioParamListener();
122fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
123fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        mCarAudioManager.setOnParameterChangeListener(listener1);
124fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        final String EVENT1 = "com.android.test.param1=10";
125fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        sendAudioParamChange(EVENT1);
126fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        listener1.waitForChange(DEFAULT_WAIT_TIMEOUT_MS, EVENT1);
127fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
128fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        mCarAudioManager.setOnParameterChangeListener(listener2);
129fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        listener1.clearParameter();
130fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        final String EVENT2 = "com.android.test.param1=20;com.android.test.param2=10";
131fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        sendAudioParamChange(EVENT2);
132fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        listener2.waitForChange(DEFAULT_WAIT_TIMEOUT_MS, EVENT2);
133fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        listener1.assertParameter(null);
134fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
135fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        mCarAudioManager.setOnParameterChangeListener(null);
136fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        listener2.clearParameter();
137fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        sendAudioParamChange(EVENT1);
138fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        Thread.sleep(200);
139fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        listener1.assertParameter(null);
140fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        listener2.assertParameter(null);
141fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park    }
142fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
143fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park    private void sendAudioParamChange(String params) {
144fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        getMockedVehicleHal().injectEvent(
145fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park                VehiclePropValueBuilder.newBuilder(VehicleProperty.AUDIO_PARAMETERS)
146fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park                .setTimestamp(SystemClock.elapsedRealtimeNanos())
147fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park                .setStringValue(params)
148fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park                .build());
149fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park    }
150fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
151fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park    static class AudioParametersPropertyHandler implements VehicleHalPropertyHandler {
152fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        private final Semaphore mSetWaitSemaphore = new Semaphore(0);
153fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
154fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        private String mValueSet;
155fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        private String mGetResponse;
156fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
157fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        public void waitForSet(long waitTimeMs, String expected) throws Exception {
158fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            mSetWaitSemaphore.tryAcquire(waitTimeMs, TimeUnit.MILLISECONDS);
159fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            synchronized (this) {
160fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park                assertEquals(expected, mValueSet);
161fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            }
162fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        }
163fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
164fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        public synchronized void setValueForGet(String value) {
165fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            mGetResponse = value;
166fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        }
167fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
168fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        @Override
169fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        public void onPropertySet(VehiclePropValue value) {
170fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            assertEquals(VehicleProperty.AUDIO_PARAMETERS, value.prop);
171fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            String setValue = value.value.stringValue;
172fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            synchronized (this) {
173fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park                mValueSet = setValue;
174fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            }
175fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            mSetWaitSemaphore.release();
176fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        }
177fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
178fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        @Override
179fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        public VehiclePropValue onPropertyGet(VehiclePropValue value) {
180fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            assertEquals(VehicleProperty.AUDIO_PARAMETERS, value.prop);
181fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            String response;
182fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            synchronized (this) {
183fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park                response = mGetResponse;
184fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            }
185fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            return VehiclePropValueBuilder.newBuilder(VehicleProperty.AUDIO_PARAMETERS)
186fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park                    .setTimestamp(SystemClock.elapsedRealtimeNanos())
187fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park                    .setStringValue(mGetResponse)
188fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park                    .build();
189fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        }
190fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
191fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        @Override
192fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        public void onPropertySubscribe(int property, int zones, float sampleRate) {
193fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            assertEquals(VehicleProperty.AUDIO_PARAMETERS, property);
194fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        }
195fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
196fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        @Override
197fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        public void onPropertyUnsubscribe(int property) {
198fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            assertEquals(VehicleProperty.AUDIO_PARAMETERS, property);
199fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        }
200fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park    }
201fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
202fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park    static class AudioParamListener implements CarAudioManager.OnParameterChangeListener {
203fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        private String mParameter;
204fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        private final Semaphore mChangeWaitSemaphore = new Semaphore(0);
205fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
206fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        @Override
207fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        public void onParameterChange(String parameters) {
208fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            mParameter = parameters;
209fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            mChangeWaitSemaphore.release();
210fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        }
211fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
212fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        public void waitForChange(long waitTimeMs, String expected) throws Exception {
213fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            mChangeWaitSemaphore.tryAcquire(waitTimeMs, TimeUnit.MILLISECONDS);
214fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            assertEquals(expected, mParameter);
215fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        }
216fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
217fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        public void clearParameter() {
218fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            mParameter = null;
219fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        }
220fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park
221fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        public void assertParameter(String expected) {
222fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park            assertEquals(expected, mParameter);
223fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park        }
224fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park    }
225fe1a8f14e1ac56f095d29336e0986950d8adfc0cKeun-young Park}
226