1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.audiopolicytest;
18 
19 import android.content.Context;
20 import android.content.pm.PackageManager;
21 import android.media.AudioAttributes;
22 import android.media.AudioManager;
23 import android.media.audiopolicy.AudioProductStrategy;
24 import android.media.audiopolicy.AudioVolumeGroup;
25 import android.test.ActivityInstrumentationTestCase2;
26 
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Map;
30 
31 public class AudioVolumesTestBase extends ActivityInstrumentationTestCase2<AudioPolicyTest> {
32     public AudioManager mAudioManager;
33     Context mContext;
34     private Map<Integer, Integer> mOriginalStreamVolumes = new HashMap<>();
35     private Map<Integer, Integer> mOriginalVolumeGroupVolumes = new HashMap<>();
36 
37     // Default matches the invalid (empty) attributes from native.
38     // The difference is the input source default which is not aligned between native and java
39     public static final AudioAttributes sDefaultAttributes =
40             AudioProductStrategy.sDefaultAttributes;
41 
42     public static final AudioAttributes sInvalidAttributes = new AudioAttributes.Builder().build();
43 
44     public final int[] PUBLIC_STREAM_TYPES = { AudioManager.STREAM_VOICE_CALL,
45             AudioManager.STREAM_SYSTEM, AudioManager.STREAM_RING, AudioManager.STREAM_MUSIC,
46             AudioManager.STREAM_ALARM, AudioManager.STREAM_NOTIFICATION,
47             AudioManager.STREAM_DTMF,  AudioManager.STREAM_ACCESSIBILITY };
48 
AudioVolumesTestBase()49     public AudioVolumesTestBase() {
50         super("com.android.audiopolicytest", AudioPolicyTest.class);
51     }
52 
53     /**
54      * <p>Note: must be called with shell permission (MODIFY_AUDIO_ROUTING)
55      */
storeAllVolumes()56     private void storeAllVolumes() {
57         List<AudioVolumeGroup> audioVolumeGroups = mAudioManager.getAudioVolumeGroups();
58         for (final AudioVolumeGroup avg : audioVolumeGroups) {
59             if (avg.getAudioAttributes().isEmpty()) {
60                 // some volume group may not supports volume control per attributes
61                 // like rerouting/patch since these groups are internal to audio policy manager
62                 continue;
63             }
64             AudioAttributes avgAttributes = sDefaultAttributes;
65             for (final AudioAttributes aa : avg.getAudioAttributes()) {
66                 if (!aa.equals(AudioProductStrategy.sDefaultAttributes)) {
67                     avgAttributes = aa;
68                     break;
69                 }
70             }
71             if (avgAttributes.equals(sDefaultAttributes)) {
72                 // This shall not happen, however, not purpose of this base class.
73                 // so bailing out.
74                 continue;
75             }
76             mOriginalVolumeGroupVolumes.put(
77                     avg.getId(), mAudioManager.getVolumeIndexForAttributes(avgAttributes));
78         }
79     }
80 
81     /**
82      * <p>Note: must be called with shell permission (MODIFY_AUDIO_ROUTING)
83      */
restoreAllVolumes()84     private void restoreAllVolumes() {
85         List<AudioVolumeGroup> audioVolumeGroups = mAudioManager.getAudioVolumeGroups();
86         for (Map.Entry<Integer, Integer> e : mOriginalVolumeGroupVolumes.entrySet()) {
87             for (final AudioVolumeGroup avg : audioVolumeGroups) {
88                 if (avg.getId() == e.getKey()) {
89                     assertTrue(!avg.getAudioAttributes().isEmpty());
90                     AudioAttributes avgAttributes = sDefaultAttributes;
91                     for (final AudioAttributes aa : avg.getAudioAttributes()) {
92                         if (!aa.equals(AudioProductStrategy.sDefaultAttributes)) {
93                             avgAttributes = aa;
94                             break;
95                         }
96                     }
97                     assertTrue(!avgAttributes.equals(sDefaultAttributes));
98                     mAudioManager.setVolumeIndexForAttributes(
99                             avgAttributes, e.getValue(), AudioManager.FLAG_ALLOW_RINGER_MODES);
100                 }
101             }
102         }
103     }
104 
105     @Override
setUp()106     protected void setUp() throws Exception {
107         super.setUp();
108 
109         mContext = getActivity();
110         mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
111 
112         assertEquals(PackageManager.PERMISSION_GRANTED,
113                 mContext.checkSelfPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING));
114 
115         // Store the original volumes that that they can be recovered in tearDown().
116         mOriginalStreamVolumes.clear();
117         for (int streamType : PUBLIC_STREAM_TYPES) {
118             mOriginalStreamVolumes.put(streamType, mAudioManager.getStreamVolume(streamType));
119         }
120         // Store the original volume per attributes so that they can be recovered in tearDown()
121         mOriginalVolumeGroupVolumes.clear();
122         storeAllVolumes();
123     }
124 
125     @Override
tearDown()126     protected void tearDown() throws Exception {
127         super.tearDown();
128 
129         // Recover the volume and the ringer mode that the test may have overwritten.
130         for (Map.Entry<Integer, Integer> e : mOriginalStreamVolumes.entrySet()) {
131             mAudioManager.setStreamVolume(e.getKey(), e.getValue(),
132                                           AudioManager.FLAG_ALLOW_RINGER_MODES);
133         }
134 
135         // Recover the original volume per attributes
136         restoreAllVolumes();
137     }
138 
resetVolumeIndex(int indexMin, int indexMax)139     public static int resetVolumeIndex(int indexMin, int indexMax) {
140         return (indexMax + indexMin) / 2;
141     }
142 
incrementVolumeIndex(int index, int indexMin, int indexMax)143     public static int incrementVolumeIndex(int index, int indexMin, int indexMax) {
144         return (index + 1 > indexMax) ? resetVolumeIndex(indexMin, indexMax) : ++index;
145     }
146 }
147