CarVolumeServiceTest.java revision 7877faa874e502ef9a20bc9299222c718873ec91
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.CarNotConnectedException;
20import android.car.media.CarAudioManager;
21import android.car.test.VehicleHalEmulator;
22import android.content.Context;
23import android.media.AudioAttributes;
24import android.media.AudioManager;
25import android.os.SystemClock;
26import android.util.Pair;
27import android.util.SparseIntArray;
28import android.view.KeyEvent;
29
30import com.android.car.vehiclenetwork.VehicleNetworkConsts;
31import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioExtFocusFlag;
32import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioFocusState;
33import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValue;
34import com.android.car.vehiclenetwork.VehiclePropConfigUtil;
35import com.android.car.vehiclenetwork.VehiclePropValueUtil;
36
37import java.util.ArrayList;
38import java.util.List;
39
40public class CarVolumeServiceTest extends MockedCarTestBase {
41    private static final int MIN_VOL = 1;
42    private static final int MAX_VOL = 20;
43    private static final long TIMEOUT_MS = 3000;
44    private static final long POLL_INTERVAL_MS = 50;
45
46    private static final int[] LOGICAL_STREAMS = {
47            AudioManager.STREAM_VOICE_CALL,
48            AudioManager.STREAM_SYSTEM,
49            AudioManager.STREAM_RING,
50            AudioManager.STREAM_MUSIC,
51            AudioManager.STREAM_ALARM,
52            AudioManager.STREAM_NOTIFICATION,
53            AudioManager.STREAM_DTMF,
54    };
55
56    private CarAudioManager mCarAudioManager;
57    private AudioManager mAudioManager;
58
59    @Override
60    protected synchronized void setUp() throws Exception {
61        super.setUp();
62        // AudioManager should be created in main thread to get focus event. :(
63        runOnMainSync(new Runnable() {
64            @Override
65            public void run() {
66                mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
67            }
68        });
69
70        List<Integer> mins = new ArrayList<>();
71        List<Integer> maxs = new ArrayList<>();
72        mins.add(MIN_VOL);
73        mins.add(MIN_VOL);
74
75        maxs.add(MAX_VOL);
76        maxs.add(MAX_VOL);
77
78        // TODO: add tests for audio context supported cases.
79        startVolumeEmulation(0 /*supported audio context*/, maxs, mins);
80        mCarAudioManager = (CarAudioManager) getCar().getCarManager(Car.AUDIO_SERVICE);
81    }
82
83    public void testVolumeLimits() throws Exception {
84        for (int stream : LOGICAL_STREAMS) {
85            assertEquals(MIN_VOL, mCarAudioManager.getStreamMinVolume(stream));
86            assertEquals(MAX_VOL, mCarAudioManager.getStreamMaxVolume(stream));
87        }
88    }
89
90    public void testVolumeSet() {
91        try {
92            int callVol = 10;
93            int musicVol = 15;
94            mCarAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, musicVol, 0);
95            mCarAudioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL, callVol, 0);
96
97            volumeVerificationPoll(createStreamVolPair(AudioManager.STREAM_MUSIC, musicVol),
98                    createStreamVolPair(AudioManager.STREAM_VOICE_CALL, callVol));
99
100            musicVol = MAX_VOL + 1;
101            mCarAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, musicVol, 0);
102
103            volumeVerificationPoll(createStreamVolPair(AudioManager.STREAM_MUSIC, MAX_VOL),
104                    createStreamVolPair(AudioManager.STREAM_VOICE_CALL, callVol));
105        } catch (CarNotConnectedException e) {
106            fail("Car not connected");
107        }
108    }
109
110    public void testVolumeKeys() throws Exception {
111        try {
112            int musicVol = 10;
113            mCarAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, musicVol, 0);
114            int callVol = 12;
115            mCarAudioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL, callVol, 0);
116
117            CarAudioFocusTest.AudioFocusListener listenerMusic =
118                    new CarAudioFocusTest.AudioFocusListener();
119            int res = mAudioManager.requestAudioFocus(listenerMusic,
120                    AudioManager.STREAM_MUSIC,
121                    AudioManager.AUDIOFOCUS_GAIN);
122            assertEquals(AudioManager.AUDIOFOCUS_REQUEST_GRANTED, res);
123            int[] request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
124            mAudioFocusPropertyHandler.sendAudioFocusState(
125                    VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN,
126                    request[1],
127                    VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_NONE_FLAG);
128
129
130            assertEquals(musicVol, mCarAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC));
131            sendVolumeKey(true /*vol up*/);
132            musicVol++;
133            volumeVerificationPoll(createStreamVolPair(AudioManager.STREAM_MUSIC, musicVol));
134
135            // call start
136            CarAudioFocusTest.AudioFocusListener listenerCall = new
137                    CarAudioFocusTest.AudioFocusListener();
138            AudioAttributes callAttrib = (new AudioAttributes.Builder()).
139                    setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION).
140                    build();
141            mAudioManager.requestAudioFocus(listenerCall, callAttrib,
142                    AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, 0);
143            request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS);
144            mAudioFocusPropertyHandler.sendAudioFocusState(
145                    VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN, request[1],
146                    VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_NONE_FLAG);
147
148            sendVolumeKey(true /*vol up*/);
149            callVol++;
150            volumeVerificationPoll(createStreamVolPair(AudioManager.STREAM_MUSIC, musicVol),
151                    createStreamVolPair(AudioManager.STREAM_VOICE_CALL, callVol));
152        } catch (CarNotConnectedException | InterruptedException e) {
153            fail(e.toString());
154        }
155    }
156
157    private Pair<Integer, Integer> createStreamVolPair(int stream, int vol) {
158        return new Pair<>(stream, vol);
159    }
160
161    private void volumeVerificationPoll(Pair<Integer, Integer>... expectedStreamVolPairs) {
162        boolean isVolExpected = false;
163        int timeElapsedMs = 0;
164        try {
165            while (!isVolExpected && timeElapsedMs <= TIMEOUT_MS) {
166                Thread.sleep(POLL_INTERVAL_MS);
167                isVolExpected = true;
168                for (Pair<Integer, Integer> vol : expectedStreamVolPairs) {
169                    if (mCarAudioManager.getStreamVolume(vol.first) != vol.second) {
170                        isVolExpected = false;
171                        break;
172                    }
173                }
174                timeElapsedMs += POLL_INTERVAL_MS;
175            }
176            assertEquals(isVolExpected, true);
177        } catch (InterruptedException | CarNotConnectedException e) {
178            fail(e.toString());
179        }
180    }
181
182    private class SingleChannelVolumeHandler implements
183            VehicleHalEmulator.VehicleHalPropertyHandler {
184        private final List<Integer> mMins;
185        private final List<Integer> mMaxs;
186        private final SparseIntArray mCurrent;
187
188        public SingleChannelVolumeHandler(List<Integer> mins, List<Integer> maxs) {
189            assertEquals(mins.size(), maxs.size());
190            mMins = mins;
191            mMaxs = maxs;
192            mCurrent = new SparseIntArray(mMins.size());
193            // initialize the vol to be the min volume.
194            for (int i = 0; i < mMins.size(); i++) {
195                mCurrent.put(i, mMins.get(i));
196            }
197        }
198
199        @Override
200        public void onPropertySet(VehiclePropValue value) {
201            int stream = value.getInt32Values(
202                    VehicleNetworkConsts.VehicleAudioVolumeIndex.VEHICLE_AUDIO_VOLUME_INDEX_STREAM);
203            int volume = value.getInt32Values(
204                    VehicleNetworkConsts.VehicleAudioVolumeIndex.VEHICLE_AUDIO_VOLUME_INDEX_VOLUME);
205            int state = value.getInt32Values(
206                    VehicleNetworkConsts.VehicleAudioVolumeIndex.VEHICLE_AUDIO_VOLUME_INDEX_STATE);
207
208            int[] values = {stream, volume, state};
209            VehiclePropValue injectValue = VehiclePropValueUtil.createIntVectorValue(
210                    VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_VOLUME, values,
211                    SystemClock.elapsedRealtimeNanos());
212            mCurrent.put(stream, volume);
213            getVehicleHalEmulator().injectEvent(injectValue);
214        }
215
216        @Override
217        public VehiclePropValue onPropertyGet(VehiclePropValue value) {
218            int stream = value.getInt32Values(
219                    VehicleNetworkConsts.VehicleAudioVolumeIndex.VEHICLE_AUDIO_VOLUME_INDEX_STREAM);
220
221            int volume = mCurrent.get(stream);
222            int[] values = {stream, volume, 0};
223            VehiclePropValue propValue = VehiclePropValueUtil.createIntVectorValue(
224                    VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_VOLUME, values,
225                    SystemClock.elapsedRealtimeNanos());
226            return propValue;
227        }
228
229        @Override
230        public void onPropertySubscribe(int property, float sampleRate, int zones) {
231        }
232
233        @Override
234        public void onPropertyUnsubscribe(int property) {
235        }
236    }
237
238    private final CarAudioFocusTest.FocusPropertyHandler mAudioFocusPropertyHandler =
239            new CarAudioFocusTest.FocusPropertyHandler(this);
240
241    private final VehicleHalEmulator.VehicleHalPropertyHandler mAudioRoutingPolicyPropertyHandler =
242            new VehicleHalEmulator.VehicleHalPropertyHandler() {
243                @Override
244                public void onPropertySet(VehiclePropValue value) {
245                    //TODO
246                }
247
248                @Override
249                public VehiclePropValue onPropertyGet(VehiclePropValue value) {
250                    fail("cannot get");
251                    return null;
252                }
253
254                @Override
255                public void onPropertySubscribe(int property, float sampleRate, int zones) {
256                    fail("cannot subscribe");
257                }
258
259                @Override
260                public void onPropertyUnsubscribe(int property) {
261                    fail("cannot unsubscribe");
262                }
263            };
264
265    private final VehicleHalEmulator.VehicleHalPropertyHandler mHWKeyHandler =
266            new VehicleHalEmulator.VehicleHalPropertyHandler() {
267                @Override
268                public void onPropertySet(VehiclePropValue value) {
269                    //TODO
270                }
271
272                @Override
273                public VehiclePropValue onPropertyGet(VehiclePropValue value) {
274                    int[] values = {0, 0, 0, 0 };
275                    return VehiclePropValueUtil.createIntVectorValue(
276                            VehicleNetworkConsts.VEHICLE_PROPERTY_HW_KEY_INPUT, values,
277                            SystemClock.elapsedRealtimeNanos());
278                }
279
280                @Override
281                public void onPropertySubscribe(int property, float sampleRate, int zones) {
282                    //
283                }
284
285                @Override
286                public void onPropertyUnsubscribe(int property) {
287                    //
288                }
289            };
290
291    private void startVolumeEmulation(int supportedAudioVolumeContext,
292                                      List<Integer> maxs, List<Integer> mins) {
293        SingleChannelVolumeHandler singleChannelVolumeHandler =
294                new SingleChannelVolumeHandler(mins, maxs);
295        int zones = (1<<maxs.size()) - 1;
296        getVehicleHalEmulator().addProperty(
297                VehiclePropConfigUtil.getBuilder(VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_VOLUME,
298                        VehicleNetworkConsts.VehiclePropAccess.VEHICLE_PROP_ACCESS_READ_WRITE,
299                        VehicleNetworkConsts.VehiclePropChangeMode
300                                .VEHICLE_PROP_CHANGE_MODE_ON_CHANGE,
301                        VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC3,
302                        VehicleNetworkConsts.VehiclePermissionModel
303                                .VEHICLE_PERMISSION_SYSTEM_APP_ONLY,
304                        supportedAudioVolumeContext /*configFlags*/,
305                        0 /*sampleRateMax*/, 0 /*sampleRateMin*/,
306                        maxs, mins).setZones(zones).build(),
307                singleChannelVolumeHandler);
308
309        getVehicleHalEmulator().addProperty(
310                VehiclePropConfigUtil.getBuilder(
311                        VehicleNetworkConsts.VEHICLE_PROPERTY_HW_KEY_INPUT,
312                        VehicleNetworkConsts.VehiclePropAccess.VEHICLE_PROP_ACCESS_READ,
313                        VehicleNetworkConsts.VehiclePropChangeMode
314                                .VEHICLE_PROP_CHANGE_MODE_ON_CHANGE,
315                        VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC4,
316                        VehicleNetworkConsts.VehiclePermissionModel
317                                .VEHICLE_PERMISSION_SYSTEM_APP_ONLY,
318                        0 /*configFlags*/, 0 /*sampleRateMax*/, 0 /*sampleRateMin*/).build(),
319                mHWKeyHandler);
320
321        getVehicleHalEmulator().addProperty(
322                VehiclePropConfigUtil.getBuilder(
323                        VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_FOCUS,
324                        VehicleNetworkConsts.VehiclePropAccess.VEHICLE_PROP_ACCESS_READ_WRITE,
325                        VehicleNetworkConsts.VehiclePropChangeMode
326                                .VEHICLE_PROP_CHANGE_MODE_ON_CHANGE,
327                        VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC4,
328                        VehicleNetworkConsts.VehiclePermissionModel
329                                .VEHICLE_PERMISSION_SYSTEM_APP_ONLY,
330                        0 /*configFlags*/, 0 /*sampleRateMax*/, 0 /*sampleRateMin*/).build(),
331                mAudioFocusPropertyHandler);
332        getVehicleHalEmulator().addProperty(
333                VehiclePropConfigUtil.getBuilder(
334                        VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_ROUTING_POLICY,
335                        VehicleNetworkConsts.VehiclePropAccess.VEHICLE_PROP_ACCESS_WRITE,
336                        VehicleNetworkConsts.VehiclePropChangeMode
337                                .VEHICLE_PROP_CHANGE_MODE_ON_CHANGE,
338                        VehicleNetworkConsts.VehicleValueType.VEHICLE_VALUE_TYPE_INT32_VEC2,
339                        VehicleNetworkConsts.VehiclePermissionModel
340                                .VEHICLE_PERMISSION_SYSTEM_APP_ONLY,
341                        0 /*configFlags*/, 0 /*sampleRateMax*/, 0 /*sampleRateMin*/).build(),
342                mAudioRoutingPolicyPropertyHandler);
343
344        getVehicleHalEmulator().addStaticProperty(
345                VehiclePropConfigUtil.createStaticStringProperty(
346                        VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_HW_VARIANT),
347                VehiclePropValueUtil.createIntValue(
348                        VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_HW_VARIANT, 1, 0));
349
350        getVehicleHalEmulator().start();
351    }
352
353    public void sendVolumeKey(boolean volUp) {
354        int[] values = {
355                VehicleNetworkConsts.VehicleHwKeyInputAction.VEHICLE_HW_KEY_INPUT_ACTION_DOWN,
356                volUp ? KeyEvent.KEYCODE_VOLUME_UP : KeyEvent.KEYCODE_VOLUME_DOWN, 0, 0 };
357
358        VehiclePropValue injectValue = VehiclePropValueUtil.createIntVectorValue(
359                VehicleNetworkConsts.VEHICLE_PROPERTY_HW_KEY_INPUT, values,
360                SystemClock.elapsedRealtimeNanos());
361
362        getVehicleHalEmulator().injectEvent(injectValue);
363
364        int[] upValues = {
365                VehicleNetworkConsts.VehicleHwKeyInputAction.VEHICLE_HW_KEY_INPUT_ACTION_UP,
366                volUp ? KeyEvent.KEYCODE_VOLUME_UP : KeyEvent.KEYCODE_VOLUME_DOWN, 0, 0 };
367
368        injectValue = VehiclePropValueUtil.createIntVectorValue(
369                VehicleNetworkConsts.VEHICLE_PROPERTY_HW_KEY_INPUT, upValues,
370                SystemClock.elapsedRealtimeNanos());
371
372        getVehicleHalEmulator().injectEvent(injectValue);
373    }
374}
375