• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.settings.bluetooth;
18 
19 import static android.media.Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL;
20 import static android.media.Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
21 
22 import static com.google.common.truth.Truth.assertThat;
23 
24 import static org.mockito.Mockito.spy;
25 import static org.mockito.Mockito.verify;
26 import static org.mockito.Mockito.when;
27 
28 import android.bluetooth.BluetoothDevice;
29 import android.media.AudioDeviceAttributes;
30 import android.media.AudioDeviceInfo;
31 import android.media.AudioManager;
32 import android.media.Spatializer;
33 
34 import androidx.preference.PreferenceCategory;
35 import androidx.preference.SwitchPreference;
36 
37 import com.android.settingslib.core.lifecycle.Lifecycle;
38 
39 import org.junit.Before;
40 import org.junit.Test;
41 import org.junit.runner.RunWith;
42 import org.mockito.Mock;
43 import org.mockito.MockitoAnnotations;
44 import org.robolectric.RobolectricTestRunner;
45 import org.robolectric.RuntimeEnvironment;
46 
47 import java.util.ArrayList;
48 import java.util.List;
49 
50 @RunWith(RobolectricTestRunner.class)
51 public class BluetoothDetailsSpatialAudioControllerTest extends BluetoothDetailsControllerTestBase {
52 
53     private static final String MAC_ADDRESS = "04:52:C7:0B:D8:3C";
54     private static final String KEY_SPATIAL_AUDIO = "spatial_audio";
55     private static final String KEY_HEAD_TRACKING = "head_tracking";
56 
57     @Mock
58     private AudioManager mAudioManager;
59     @Mock
60     private Spatializer mSpatializer;
61     @Mock
62     private Lifecycle mSpatialAudioLifecycle;
63     @Mock
64     private PreferenceCategory mProfilesContainer;
65     @Mock
66     private BluetoothDevice mBluetoothDevice;
67 
68     private AudioDeviceAttributes mAvailableDevice;
69 
70     private BluetoothDetailsSpatialAudioController mController;
71     private SwitchPreference mSpatialAudioPref;
72     private SwitchPreference mHeadTrackingPref;
73 
74     @Before
setUp()75     public void setUp() {
76         MockitoAnnotations.initMocks(this);
77 
78         mContext = spy(RuntimeEnvironment.application);
79         when(mContext.getSystemService(AudioManager.class)).thenReturn(mAudioManager);
80         when(mAudioManager.getSpatializer()).thenReturn(mSpatializer);
81         when(mCachedDevice.getAddress()).thenReturn(MAC_ADDRESS);
82         when(mCachedDevice.getDevice()).thenReturn(mBluetoothDevice);
83         when(mBluetoothDevice.getAnonymizedAddress()).thenReturn(MAC_ADDRESS);
84 
85         mController = new BluetoothDetailsSpatialAudioController(mContext, mFragment,
86                 mCachedDevice, mSpatialAudioLifecycle);
87         mController.mProfilesContainer = mProfilesContainer;
88 
89         mSpatialAudioPref = mController.createSpatialAudioPreference(mContext);
90         mHeadTrackingPref = mController.createHeadTrackingPreference(mContext);
91 
92         when(mProfilesContainer.findPreference(KEY_SPATIAL_AUDIO)).thenReturn(mSpatialAudioPref);
93         when(mProfilesContainer.findPreference(KEY_HEAD_TRACKING)).thenReturn(mHeadTrackingPref);
94 
95         mAvailableDevice = new AudioDeviceAttributes(
96                 AudioDeviceAttributes.ROLE_OUTPUT,
97                 AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
98                 MAC_ADDRESS);
99     }
100 
101     @Test
isAvailable_forSpatializerWithLevelNone_returnsFalse()102     public void isAvailable_forSpatializerWithLevelNone_returnsFalse() {
103         when(mSpatializer.getImmersiveAudioLevel()).thenReturn(SPATIALIZER_IMMERSIVE_LEVEL_NONE);
104         assertThat(mController.isAvailable()).isFalse();
105     }
106 
107     @Test
isAvailable_forSpatializerWithLevelNotNone_returnsTrue()108     public void isAvailable_forSpatializerWithLevelNotNone_returnsTrue() {
109         when(mSpatializer.getImmersiveAudioLevel()).thenReturn(
110                 SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL);
111         assertThat(mController.isAvailable()).isTrue();
112     }
113 
114     @Test
refresh_spatialAudioIsTurnedOn_checksSpatialAudioPreference()115     public void refresh_spatialAudioIsTurnedOn_checksSpatialAudioPreference() {
116         List<AudioDeviceAttributes> compatibleAudioDevices = new ArrayList<>();
117         mController.setAvailableDevice(mAvailableDevice);
118         compatibleAudioDevices.add(mController.mAudioDevice);
119         when(mSpatializer.isAvailableForDevice(mController.mAudioDevice)).thenReturn(true);
120         when(mSpatializer.getCompatibleAudioDevices()).thenReturn(compatibleAudioDevices);
121 
122         mController.refresh();
123 
124         assertThat(mSpatialAudioPref.isChecked()).isTrue();
125     }
126 
127     @Test
refresh_spatialAudioIsTurnedOff_unchecksSpatialAudioPreference()128     public void refresh_spatialAudioIsTurnedOff_unchecksSpatialAudioPreference() {
129         List<AudioDeviceAttributes> compatibleAudioDevices = new ArrayList<>();
130         when(mSpatializer.getCompatibleAudioDevices()).thenReturn(compatibleAudioDevices);
131 
132         mController.refresh();
133 
134         assertThat(mSpatialAudioPref.isChecked()).isFalse();
135     }
136 
137     @Test
refresh_spatialAudioOnAndHeadTrackingIsAvailable_showsHeadTrackingPreference()138     public void refresh_spatialAudioOnAndHeadTrackingIsAvailable_showsHeadTrackingPreference() {
139         List<AudioDeviceAttributes> compatibleAudioDevices = new ArrayList<>();
140         compatibleAudioDevices.add(mController.mAudioDevice);
141         when(mSpatializer.getCompatibleAudioDevices()).thenReturn(compatibleAudioDevices);
142         when(mSpatializer.hasHeadTracker(mController.mAudioDevice)).thenReturn(true);
143 
144         mController.refresh();
145 
146         assertThat(mHeadTrackingPref.isVisible()).isTrue();
147     }
148 
149     @Test
150     public void
refresh_spatialAudioOnAndHeadTrackingIsNotAvailable_hidesHeadTrackingPreference()151             refresh_spatialAudioOnAndHeadTrackingIsNotAvailable_hidesHeadTrackingPreference() {
152         List<AudioDeviceAttributes> compatibleAudioDevices = new ArrayList<>();
153         mController.setAvailableDevice(mAvailableDevice);
154         compatibleAudioDevices.add(mController.mAudioDevice);
155         when(mSpatializer.getCompatibleAudioDevices()).thenReturn(compatibleAudioDevices);
156         when(mSpatializer.hasHeadTracker(mController.mAudioDevice)).thenReturn(false);
157 
158         mController.refresh();
159 
160         verify(mProfilesContainer).removePreference(mHeadTrackingPref);
161     }
162 
163     @Test
refresh_spatialAudioOff_hidesHeadTrackingPreference()164     public void refresh_spatialAudioOff_hidesHeadTrackingPreference() {
165         List<AudioDeviceAttributes> compatibleAudioDevices = new ArrayList<>();
166         when(mSpatializer.getCompatibleAudioDevices()).thenReturn(compatibleAudioDevices);
167 
168         mController.refresh();
169 
170         verify(mProfilesContainer).removePreference(mHeadTrackingPref);
171     }
172 
173     @Test
refresh_headTrackingIsTurnedOn_checksHeadTrackingPreference()174     public void refresh_headTrackingIsTurnedOn_checksHeadTrackingPreference() {
175         List<AudioDeviceAttributes> compatibleAudioDevices = new ArrayList<>();
176         mController.setAvailableDevice(mAvailableDevice);
177         compatibleAudioDevices.add(mController.mAudioDevice);
178         when(mSpatializer.getCompatibleAudioDevices()).thenReturn(compatibleAudioDevices);
179         when(mSpatializer.isAvailableForDevice(mController.mAudioDevice)).thenReturn(true);
180         when(mSpatializer.hasHeadTracker(mController.mAudioDevice)).thenReturn(true);
181         when(mSpatializer.isHeadTrackerEnabled(mController.mAudioDevice)).thenReturn(true);
182 
183         mController.refresh();
184 
185         assertThat(mHeadTrackingPref.isChecked()).isTrue();
186     }
187 
188     @Test
refresh_headTrackingIsTurnedOff_unchecksHeadTrackingPreference()189     public void refresh_headTrackingIsTurnedOff_unchecksHeadTrackingPreference() {
190         List<AudioDeviceAttributes> compatibleAudioDevices = new ArrayList<>();
191         mController.setAvailableDevice(mAvailableDevice);
192         compatibleAudioDevices.add(mController.mAudioDevice);
193         when(mSpatializer.getCompatibleAudioDevices()).thenReturn(compatibleAudioDevices);
194         when(mSpatializer.isAvailableForDevice(mController.mAudioDevice)).thenReturn(true);
195         when(mSpatializer.hasHeadTracker(mController.mAudioDevice)).thenReturn(true);
196         when(mSpatializer.isHeadTrackerEnabled(mController.mAudioDevice)).thenReturn(false);
197 
198         mController.refresh();
199 
200         assertThat(mHeadTrackingPref.isChecked()).isFalse();
201     }
202 
203     @Test
turnedOnSpatialAudio_invokesAddCompatibleAudioDevice()204     public void turnedOnSpatialAudio_invokesAddCompatibleAudioDevice() {
205         mController.setAvailableDevice(mAvailableDevice);
206         mSpatialAudioPref.setChecked(true);
207         mController.onPreferenceClick(mSpatialAudioPref);
208         verify(mSpatializer).addCompatibleAudioDevice(mController.mAudioDevice);
209     }
210 
211     @Test
turnedOffSpatialAudio_invokesRemoveCompatibleAudioDevice()212     public void turnedOffSpatialAudio_invokesRemoveCompatibleAudioDevice() {
213         mController.setAvailableDevice(mAvailableDevice);
214         mSpatialAudioPref.setChecked(false);
215         mController.onPreferenceClick(mSpatialAudioPref);
216         verify(mSpatializer).removeCompatibleAudioDevice(mController.mAudioDevice);
217     }
218 
219     @Test
turnedOnHeadTracking_invokesSetHeadTrackerEnabled_setsTrue()220     public void turnedOnHeadTracking_invokesSetHeadTrackerEnabled_setsTrue() {
221         mController.setAvailableDevice(mAvailableDevice);
222         mHeadTrackingPref.setChecked(true);
223         mController.onPreferenceClick(mHeadTrackingPref);
224         verify(mSpatializer).setHeadTrackerEnabled(true, mController.mAudioDevice);
225     }
226 
227     @Test
turnedOffHeadTracking_invokesSetHeadTrackerEnabled_setsFalse()228     public void turnedOffHeadTracking_invokesSetHeadTrackerEnabled_setsFalse() {
229         mController.setAvailableDevice(mAvailableDevice);
230         mHeadTrackingPref.setChecked(false);
231         mController.onPreferenceClick(mHeadTrackingPref);
232         verify(mSpatializer).setHeadTrackerEnabled(false, mController.mAudioDevice);
233     }
234 }
235