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