• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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.bluetooth.BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
20 import static android.bluetooth.BluetoothHapClient.PRESET_INDEX_UNAVAILABLE;
21 
22 import static com.android.settings.bluetooth.BluetoothDetailsHearingDeviceController.KEY_HEARING_DEVICE_GROUP;
23 import static com.android.settings.bluetooth.BluetoothDetailsHearingAidsPresetsController.KEY_HEARING_AIDS_PRESETS;
24 
25 import static com.google.common.truth.Truth.assertThat;
26 
27 import static org.mockito.ArgumentMatchers.any;
28 import static org.mockito.Mockito.mock;
29 import static org.mockito.Mockito.never;
30 import static org.mockito.Mockito.spy;
31 import static org.mockito.Mockito.verify;
32 import static org.mockito.Mockito.when;
33 
34 import android.bluetooth.BluetoothDevice;
35 import android.bluetooth.BluetoothHapClient;
36 import android.bluetooth.BluetoothHapPresetInfo;
37 
38 import androidx.preference.ListPreference;
39 import androidx.preference.PreferenceCategory;
40 
41 import com.android.settings.R;
42 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
43 import com.android.settingslib.bluetooth.HapClientProfile;
44 import com.android.settingslib.bluetooth.LocalBluetoothManager;
45 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
46 
47 import org.junit.Rule;
48 import org.junit.Test;
49 import org.junit.runner.RunWith;
50 import org.mockito.Mock;
51 import org.mockito.junit.MockitoJUnit;
52 import org.mockito.junit.MockitoRule;
53 import org.robolectric.RobolectricTestRunner;
54 
55 import java.util.ArrayList;
56 import java.util.List;
57 import java.util.Set;
58 import java.util.concurrent.Executor;
59 
60 /** Tests for {@link BluetoothDetailsHearingAidsPresetsController}. */
61 @RunWith(RobolectricTestRunner.class)
62 public class BluetoothDetailsHearingAidsPresetsControllerTest extends
63         BluetoothDetailsControllerTestBase {
64 
65     private static final int TEST_PRESET_INDEX = 1;
66     private static final String TEST_PRESET_NAME = "test_preset";
67     private static final int TEST_HAP_GROUP_ID = 1;
68 
69     @Rule
70     public final MockitoRule mockito = MockitoJUnit.rule();
71 
72     @Mock
73     private LocalBluetoothManager mLocalManager;
74     @Mock
75     private LocalBluetoothProfileManager mProfileManager;
76     @Mock
77     private HapClientProfile mHapClientProfile;
78     @Mock
79     private CachedBluetoothDevice mCachedChildDevice;
80     @Mock
81     private BluetoothDevice mChildDevice;
82 
83     private BluetoothDetailsHearingAidsPresetsController mController;
84 
85     @Override
setUp()86     public void setUp() {
87         super.setUp();
88 
89         when(mLocalManager.getProfileManager()).thenReturn(mProfileManager);
90         when(mProfileManager.getHapClientProfile()).thenReturn(mHapClientProfile);
91         when(mCachedDevice.getDevice()).thenReturn(mDevice);
92         when(mCachedDevice.getProfiles()).thenReturn(List.of(mHapClientProfile));
93         when(mCachedDevice.isConnectedHapClientDevice()).thenReturn(true);
94         when(mCachedChildDevice.getDevice()).thenReturn(mChildDevice);
95         PreferenceCategory deviceControls = new PreferenceCategory(mContext);
96         deviceControls.setKey(KEY_HEARING_DEVICE_GROUP);
97         mScreen.addPreference(deviceControls);
98         mController = new BluetoothDetailsHearingAidsPresetsController(mContext, mFragment,
99                 mLocalManager, mCachedDevice, mLifecycle);
100         mController.init(mScreen);
101     }
102 
103     @Test
isAvailable_supportHap_returnTrue()104     public void isAvailable_supportHap_returnTrue() {
105         when(mCachedDevice.getProfiles()).thenReturn(List.of(mHapClientProfile));
106 
107         assertThat(mController.isAvailable()).isTrue();
108     }
109 
110     @Test
isAvailable_notSupportHap_returnFalse()111     public void isAvailable_notSupportHap_returnFalse() {
112         when(mCachedDevice.getProfiles()).thenReturn(new ArrayList<>());
113 
114         assertThat(mController.isAvailable()).isFalse();
115     }
116 
117     @Test
onResume_registerCallback()118     public void onResume_registerCallback() {
119         mController.onResume();
120 
121         verify(mHapClientProfile).registerCallback(any(Executor.class),
122                 any(BluetoothHapClient.Callback.class));
123     }
124 
125     @Test
onPause_unregisterCallback()126     public void onPause_unregisterCallback() {
127         mController.onPause();
128 
129         verify(mHapClientProfile).unregisterCallback(any(BluetoothHapClient.Callback.class));
130     }
131 
132     @Test
onPreferenceChange_keyMatched_verifyStatusUpdated()133     public void onPreferenceChange_keyMatched_verifyStatusUpdated() {
134         final ListPreference presetPreference = getTestPresetPreference(KEY_HEARING_AIDS_PRESETS);
135 
136         boolean handled = mController.onPreferenceChange(presetPreference,
137                 String.valueOf(TEST_PRESET_INDEX));
138 
139         assertThat(handled).isTrue();
140         verify(presetPreference).setSummary(TEST_PRESET_NAME);
141     }
142 
143     @Test
onPreferenceChange_keyNotMatched_doNothing()144     public void onPreferenceChange_keyNotMatched_doNothing() {
145         final ListPreference presetPreference = getTestPresetPreference("wrong_key");
146 
147         boolean handled = mController.onPreferenceChange(
148                 presetPreference, String.valueOf(TEST_PRESET_INDEX));
149 
150         assertThat(handled).isFalse();
151         verify(presetPreference, never()).setSummary(any());
152     }
153 
154     @Test
onPreferenceChange_supportGroupOperation_validGroupId_verifySelectPresetForGroup()155     public void onPreferenceChange_supportGroupOperation_validGroupId_verifySelectPresetForGroup() {
156         final ListPreference presetPreference = getTestPresetPreference(KEY_HEARING_AIDS_PRESETS);
157         when(mHapClientProfile.supportsSynchronizedPresets(mDevice)).thenReturn(true);
158         when(mHapClientProfile.getHapGroup(mDevice)).thenReturn(TEST_HAP_GROUP_ID);
159 
160         mController.onPreferenceChange(presetPreference, String.valueOf(TEST_PRESET_INDEX));
161 
162         verify(mHapClientProfile).selectPresetForGroup(TEST_HAP_GROUP_ID, TEST_PRESET_INDEX);
163     }
164 
165     @Test
onPreferenceChange_notSupportGroupOperation_verifySelectPreset()166     public void onPreferenceChange_notSupportGroupOperation_verifySelectPreset() {
167         final ListPreference presetPreference = getTestPresetPreference(KEY_HEARING_AIDS_PRESETS);
168         when(mHapClientProfile.supportsSynchronizedPresets(mDevice)).thenReturn(false);
169         when(mHapClientProfile.getHapGroup(mDevice)).thenReturn(TEST_HAP_GROUP_ID);
170 
171         mController.onPreferenceChange(presetPreference, String.valueOf(TEST_PRESET_INDEX));
172 
173         verify(mHapClientProfile).selectPreset(mDevice, TEST_PRESET_INDEX);
174     }
175 
176     @Test
onPreferenceChange_invalidGroupId_verifySelectPreset()177     public void onPreferenceChange_invalidGroupId_verifySelectPreset() {
178         final ListPreference presetPreference = getTestPresetPreference(KEY_HEARING_AIDS_PRESETS);
179         when(mHapClientProfile.supportsSynchronizedPresets(mDevice)).thenReturn(true);
180         when(mHapClientProfile.getHapGroup(mDevice)).thenReturn(GROUP_ID_INVALID);
181 
182         mController.onPreferenceChange(presetPreference, String.valueOf(TEST_PRESET_INDEX));
183 
184         verify(mHapClientProfile).selectPreset(mDevice, TEST_PRESET_INDEX);
185     }
186 
187     @Test
onPreferenceChange_notSupportGroupOperation_hasSubDevice_verifyStatusUpdated()188     public void onPreferenceChange_notSupportGroupOperation_hasSubDevice_verifyStatusUpdated() {
189         final ListPreference presetPreference = getTestPresetPreference(KEY_HEARING_AIDS_PRESETS);
190         when(mHapClientProfile.supportsSynchronizedPresets(mDevice)).thenReturn(false);
191         when(mCachedDevice.getSubDevice()).thenReturn(mCachedChildDevice);
192 
193         mController.onPreferenceChange(presetPreference, String.valueOf(TEST_PRESET_INDEX));
194 
195         verify(mHapClientProfile).selectPreset(mDevice, TEST_PRESET_INDEX);
196         verify(mHapClientProfile).selectPreset(mChildDevice, TEST_PRESET_INDEX);
197     }
198 
199     @Test
onPreferenceChange_notSupportGroupOperation_hasMemberDevice_verifyStatusUpdated()200     public void onPreferenceChange_notSupportGroupOperation_hasMemberDevice_verifyStatusUpdated() {
201         final ListPreference presetPreference = getTestPresetPreference(KEY_HEARING_AIDS_PRESETS);
202         when(mHapClientProfile.supportsSynchronizedPresets(mDevice)).thenReturn(false);
203         when(mCachedDevice.getMemberDevice()).thenReturn(Set.of(mCachedChildDevice));
204 
205         mController.onPreferenceChange(presetPreference, String.valueOf(TEST_PRESET_INDEX));
206 
207         verify(mHapClientProfile).selectPreset(mDevice, TEST_PRESET_INDEX);
208         verify(mHapClientProfile).selectPreset(mChildDevice, TEST_PRESET_INDEX);
209     }
210 
211     @Test
refresh_emptyPresetInfo_preferenceDisabled()212     public void refresh_emptyPresetInfo_preferenceDisabled() {
213         when(mHapClientProfile.getAllPresetInfo(mDevice)).thenReturn(new ArrayList<>());
214 
215         mController.refresh();
216 
217         assertThat(mController.getPreference()).isNotNull();
218         assertThat(mController.getPreference().isEnabled()).isFalse();
219         assertThat(String.valueOf(mController.getPreference().getSummary())).isEqualTo(
220                 mContext.getString(R.string.bluetooth_hearing_aids_presets_empty_list_message));
221     }
222 
223     @Test
refresh_validPresetInfo_preferenceEnabled()224     public void refresh_validPresetInfo_preferenceEnabled() {
225         BluetoothHapPresetInfo info = getTestPresetInfo(true);
226         when(mHapClientProfile.getAllPresetInfo(mDevice)).thenReturn(List.of(info));
227 
228         mController.refresh();
229 
230         assertThat(mController.getPreference()).isNotNull();
231         assertThat(mController.getPreference().isEnabled()).isTrue();
232     }
233 
234     @Test
refresh_invalidActivePresetIndex_summaryIsNull()235     public void refresh_invalidActivePresetIndex_summaryIsNull() {
236         BluetoothHapPresetInfo info = getTestPresetInfo(true);
237         when(mHapClientProfile.getAllPresetInfo(mDevice)).thenReturn(List.of(info));
238         when(mHapClientProfile.getActivePresetIndex(mDevice)).thenReturn(PRESET_INDEX_UNAVAILABLE);
239 
240         mController.refresh();
241 
242         assertThat(mController.getPreference()).isNotNull();
243         assertThat(mController.getPreference().getSummary()).isNull();
244     }
245 
246     @Test
refresh_validActivePresetIndex_summaryIsNotNull()247     public void refresh_validActivePresetIndex_summaryIsNotNull() {
248         BluetoothHapPresetInfo info = getTestPresetInfo(true);
249         when(mHapClientProfile.getAllPresetInfo(mDevice)).thenReturn(List.of(info));
250         when(mHapClientProfile.getActivePresetIndex(mDevice)).thenReturn(TEST_PRESET_INDEX);
251 
252         mController.refresh();
253 
254         assertThat(mController.getPreference()).isNotNull();
255         assertThat(mController.getPreference().getSummary()).isNotNull();
256     }
257 
258     @Test
onPresetSelectionForGroupFailed_selectPresetIsCalled()259     public void onPresetSelectionForGroupFailed_selectPresetIsCalled() {
260         when(mHapClientProfile.getHapGroup(mDevice)).thenReturn(TEST_HAP_GROUP_ID);
261         mController.getPreference().setValue(String.valueOf(TEST_PRESET_INDEX));
262 
263         mController.onPresetSelectionForGroupFailed(TEST_HAP_GROUP_ID, TEST_PRESET_INDEX);
264 
265         verify(mHapClientProfile).selectPreset(mDevice, TEST_PRESET_INDEX);
266     }
267 
268     @Test
loadAllPresetInfo_unavailablePreset_notAddedToEntries()269     public void loadAllPresetInfo_unavailablePreset_notAddedToEntries() {
270         BluetoothHapPresetInfo info = getTestPresetInfo(false);
271         when(mHapClientProfile.getAllPresetInfo(mDevice)).thenReturn(List.of(info));
272 
273         mController.refresh();
274 
275         assertThat(mController.getPreference().getEntries().length).isEqualTo(0);
276     }
277 
278     @Test
loadAllPresetInfo_availablePreset_addedToEntries()279     public void loadAllPresetInfo_availablePreset_addedToEntries() {
280         BluetoothHapPresetInfo info = getTestPresetInfo(true);
281         when(mHapClientProfile.getAllPresetInfo(mDevice)).thenReturn(List.of(info));
282 
283         mController.refresh();
284 
285         assertThat(mController.getPreference().getEntries().length).isEqualTo(1);
286     }
getTestPresetInfo(boolean available)287     private BluetoothHapPresetInfo getTestPresetInfo(boolean available) {
288         BluetoothHapPresetInfo info = mock(BluetoothHapPresetInfo.class);
289         when(info.getName()).thenReturn(TEST_PRESET_NAME);
290         when(info.getIndex()).thenReturn(TEST_PRESET_INDEX);
291         when(info.isAvailable()).thenReturn(available);
292         return info;
293     }
294 
getTestPresetPreference(String key)295     private ListPreference getTestPresetPreference(String key) {
296         final ListPreference presetPreference = spy(new ListPreference(mContext));
297         when(presetPreference.findIndexOfValue(String.valueOf(TEST_PRESET_INDEX))).thenReturn(0);
298         when(presetPreference.getEntries()).thenReturn(new CharSequence[]{TEST_PRESET_NAME});
299         when(presetPreference.getEntryValues()).thenReturn(
300                 new CharSequence[]{String.valueOf(TEST_PRESET_INDEX)});
301         presetPreference.setKey(key);
302         return presetPreference;
303     }
304 }
305