1 /* 2 * Copyright (C) 2017 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 package com.android.settingslib.bluetooth; 17 18 import static com.google.common.truth.Truth.assertThat; 19 20 import static org.mockito.ArgumentMatchers.any; 21 import static org.mockito.ArgumentMatchers.anyString; 22 import static org.mockito.Mockito.doAnswer; 23 import static org.mockito.Mockito.doReturn; 24 import static org.mockito.Mockito.mock; 25 import static org.mockito.Mockito.never; 26 import static org.mockito.Mockito.spy; 27 import static org.mockito.Mockito.verify; 28 import static org.mockito.Mockito.when; 29 30 import android.bluetooth.BluetoothAdapter; 31 import android.bluetooth.BluetoothDevice; 32 import android.bluetooth.BluetoothLeAudio; 33 import android.bluetooth.BluetoothProfile; 34 import android.bluetooth.BluetoothStatusCodes; 35 import android.content.Context; 36 import android.graphics.drawable.BitmapDrawable; 37 import android.media.AudioManager; 38 import android.util.LruCache; 39 40 import com.android.settingslib.R; 41 import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter; 42 import com.android.settingslib.widget.AdaptiveOutlineDrawable; 43 44 import org.junit.Before; 45 import org.junit.Test; 46 import org.junit.runner.RunWith; 47 import org.mockito.Mock; 48 import org.mockito.MockitoAnnotations; 49 import org.robolectric.RobolectricTestRunner; 50 import org.robolectric.RuntimeEnvironment; 51 import org.robolectric.annotation.Config; 52 import org.robolectric.shadow.api.Shadow; 53 54 @RunWith(RobolectricTestRunner.class) 55 @Config(shadows = {ShadowBluetoothAdapter.class}) 56 public class CachedBluetoothDeviceTest { 57 private static final String DEVICE_NAME = "TestName"; 58 private static final String DEVICE_ALIAS = "TestAlias"; 59 private static final String DEVICE_ADDRESS = "AA:BB:CC:DD:EE:FF"; 60 private static final String DEVICE_ALIAS_NEW = "TestAliasNew"; 61 private static final String TWS_BATTERY_LEFT = "15"; 62 private static final String TWS_BATTERY_RIGHT = "25"; 63 private static final short RSSI_1 = 10; 64 private static final short RSSI_2 = 11; 65 private static final boolean JUSTDISCOVERED_1 = true; 66 private static final boolean JUSTDISCOVERED_2 = false; 67 @Mock 68 private LocalBluetoothProfileManager mProfileManager; 69 @Mock 70 private HeadsetProfile mHfpProfile; 71 @Mock 72 private A2dpProfile mA2dpProfile; 73 @Mock 74 private PanProfile mPanProfile; 75 @Mock 76 private HearingAidProfile mHearingAidProfile; 77 @Mock 78 private HapClientProfile mHapClientProfile; 79 @Mock 80 private LeAudioProfile mLeAudioProfile; 81 @Mock 82 private BluetoothDevice mDevice; 83 @Mock 84 private BluetoothDevice mSubDevice; 85 private CachedBluetoothDevice mCachedDevice; 86 private CachedBluetoothDevice mSubCachedDevice; 87 private AudioManager mAudioManager; 88 private Context mContext; 89 private int mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; 90 private ShadowBluetoothAdapter mShadowBluetoothAdapter; 91 92 @Before setUp()93 public void setUp() { 94 MockitoAnnotations.initMocks(this); 95 mContext = RuntimeEnvironment.application; 96 mAudioManager = mContext.getSystemService(AudioManager.class); 97 mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter()); 98 when(mDevice.getAddress()).thenReturn(DEVICE_ADDRESS); 99 when(mHfpProfile.isProfileReady()).thenReturn(true); 100 when(mHfpProfile.getProfileId()).thenReturn(BluetoothProfile.HEADSET); 101 when(mA2dpProfile.isProfileReady()).thenReturn(true); 102 when(mA2dpProfile.getProfileId()).thenReturn(BluetoothProfile.A2DP); 103 when(mPanProfile.isProfileReady()).thenReturn(true); 104 when(mPanProfile.getProfileId()).thenReturn(BluetoothProfile.PAN); 105 when(mHearingAidProfile.isProfileReady()).thenReturn(true); 106 when(mHearingAidProfile.getProfileId()).thenReturn(BluetoothProfile.HEARING_AID); 107 when(mLeAudioProfile.isProfileReady()).thenReturn(true); 108 when(mLeAudioProfile.getProfileId()).thenReturn(BluetoothProfile.LE_AUDIO); 109 mCachedDevice = spy(new CachedBluetoothDevice(mContext, mProfileManager, mDevice)); 110 mSubCachedDevice = spy(new CachedBluetoothDevice(mContext, mProfileManager, mSubDevice)); 111 doAnswer((invocation) -> mBatteryLevel).when(mCachedDevice).getBatteryLevel(); 112 doAnswer((invocation) -> mBatteryLevel).when(mSubCachedDevice).getBatteryLevel(); 113 } 114 testTransitionFromConnectingToDisconnected( LocalBluetoothProfile connectingProfile, LocalBluetoothProfile connectedProfile, int connectionPolicy, String expectedSummary)115 private void testTransitionFromConnectingToDisconnected( 116 LocalBluetoothProfile connectingProfile, LocalBluetoothProfile connectedProfile, 117 int connectionPolicy, String expectedSummary) { 118 // Arrange: 119 // At least one profile has to be connected 120 updateProfileStatus(connectedProfile, BluetoothProfile.STATE_CONNECTED); 121 // Set profile under test to CONNECTING 122 updateProfileStatus(connectingProfile, BluetoothProfile.STATE_CONNECTING); 123 // Set connection policy 124 when(connectingProfile.getConnectionPolicy(mDevice)).thenReturn(connectionPolicy); 125 126 // Act & Assert: 127 // Get the expected connection summary. 128 updateProfileStatus(connectingProfile, BluetoothProfile.STATE_DISCONNECTED); 129 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(expectedSummary); 130 } 131 132 @Test onProfileStateChanged_testConnectingToDisconnected_policyAllowed_problem()133 public void onProfileStateChanged_testConnectingToDisconnected_policyAllowed_problem() { 134 String connectTimeoutString = mContext.getString(R.string.profile_connect_timeout_subtext); 135 136 testTransitionFromConnectingToDisconnected(mA2dpProfile, mLeAudioProfile, 137 BluetoothProfile.CONNECTION_POLICY_ALLOWED, connectTimeoutString); 138 testTransitionFromConnectingToDisconnected(mHearingAidProfile, mLeAudioProfile, 139 BluetoothProfile.CONNECTION_POLICY_ALLOWED, connectTimeoutString); 140 testTransitionFromConnectingToDisconnected(mHfpProfile, mLeAudioProfile, 141 BluetoothProfile.CONNECTION_POLICY_ALLOWED, connectTimeoutString); 142 testTransitionFromConnectingToDisconnected(mLeAudioProfile, mA2dpProfile, 143 BluetoothProfile.CONNECTION_POLICY_ALLOWED, connectTimeoutString); 144 } 145 146 @Test onProfileStateChanged_testConnectingToDisconnected_policyForbidden_noProblem()147 public void onProfileStateChanged_testConnectingToDisconnected_policyForbidden_noProblem() { 148 testTransitionFromConnectingToDisconnected(mA2dpProfile, mLeAudioProfile, 149 BluetoothProfile.CONNECTION_POLICY_FORBIDDEN, null); 150 testTransitionFromConnectingToDisconnected(mHearingAidProfile, mLeAudioProfile, 151 BluetoothProfile.CONNECTION_POLICY_FORBIDDEN, null); 152 testTransitionFromConnectingToDisconnected(mHfpProfile, mLeAudioProfile, 153 BluetoothProfile.CONNECTION_POLICY_FORBIDDEN, null); 154 testTransitionFromConnectingToDisconnected(mLeAudioProfile, mA2dpProfile, 155 BluetoothProfile.CONNECTION_POLICY_FORBIDDEN, null); 156 } 157 158 @Test onProfileStateChanged_testConnectingToDisconnected_policyUnknown_noProblem()159 public void onProfileStateChanged_testConnectingToDisconnected_policyUnknown_noProblem() { 160 testTransitionFromConnectingToDisconnected(mA2dpProfile, mLeAudioProfile, 161 BluetoothProfile.CONNECTION_POLICY_UNKNOWN, null); 162 testTransitionFromConnectingToDisconnected(mHearingAidProfile, mLeAudioProfile, 163 BluetoothProfile.CONNECTION_POLICY_UNKNOWN, null); 164 testTransitionFromConnectingToDisconnected(mHfpProfile, mLeAudioProfile, 165 BluetoothProfile.CONNECTION_POLICY_UNKNOWN, null); 166 testTransitionFromConnectingToDisconnected(mLeAudioProfile, mA2dpProfile, 167 BluetoothProfile.CONNECTION_POLICY_UNKNOWN, null); 168 } 169 170 @Test getConnectionSummary_testProfilesInactive_returnPairing()171 public void getConnectionSummary_testProfilesInactive_returnPairing() { 172 // Arrange: 173 // Bond State: Bonding 174 when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDING); 175 176 // Act & Assert: 177 // Get "Pairing…" result without Battery Level. 178 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Pairing…"); 179 } 180 181 @Test getConnectionSummary_testSingleProfileConnectDisconnect()182 public void getConnectionSummary_testSingleProfileConnectDisconnect() { 183 // Test without battery level 184 // Set PAN profile to be connected and test connection state summary 185 updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED); 186 assertThat(mCachedDevice.getConnectionSummary()).isNull(); 187 188 // Set PAN profile to be disconnected and test connection state summary 189 updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); 190 assertThat(mCachedDevice.getConnectionSummary()).isNull(); 191 192 // Test with battery level 193 mBatteryLevel = 10; 194 // Set PAN profile to be connected and test connection state summary 195 updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED); 196 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("10% battery"); 197 198 // Set PAN profile to be disconnected and test connection state summary 199 updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); 200 assertThat(mCachedDevice.getConnectionSummary()).isNull(); 201 202 // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level 203 mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; 204 205 // Set PAN profile to be connected and test connection state summary 206 updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED); 207 assertThat(mCachedDevice.getConnectionSummary()).isNull(); 208 209 // Set PAN profile to be disconnected and test connection state summary 210 updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); 211 assertThat(mCachedDevice.getConnectionSummary()).isNull(); 212 } 213 214 @Test getConnectionSummary_testMultipleProfileConnectDisconnect()215 public void getConnectionSummary_testMultipleProfileConnectDisconnect() { 216 mBatteryLevel = 10; 217 218 // Set HFP, A2DP and PAN profile to be connected and test connection state summary 219 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); 220 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); 221 updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED); 222 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("10% battery"); 223 224 // Disconnect HFP only and test connection state summary 225 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); 226 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo( 227 "10% battery"); 228 229 // Disconnect A2DP only and test connection state summary 230 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); 231 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); 232 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo( 233 "10% battery"); 234 235 // Disconnect both HFP and A2DP and test connection state summary 236 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); 237 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo( 238 "10% battery"); 239 240 // Disconnect all profiles and test connection state summary 241 updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); 242 assertThat(mCachedDevice.getConnectionSummary()).isNull(); 243 } 244 245 @Test getConnectionSummary_testSingleProfileActiveDeviceA2dp()246 public void getConnectionSummary_testSingleProfileActiveDeviceA2dp() { 247 // Test without battery level 248 // Set A2DP profile to be connected and test connection state summary 249 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); 250 assertThat(mCachedDevice.getConnectionSummary()).isNull(); 251 252 // Set device as Active for A2DP and test connection state summary 253 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); 254 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active"); 255 256 // Test with battery level 257 mBatteryLevel = 10; 258 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo( 259 "Active, 10% battery"); 260 261 // Set A2DP profile to be disconnected and test connection state summary 262 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); 263 assertThat(mCachedDevice.getConnectionSummary()).isNull(); 264 265 // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level 266 mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; 267 // Set A2DP profile to be connected, Active and test connection state summary 268 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); 269 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); 270 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active"); 271 272 // Set A2DP profile to be disconnected and test connection state summary 273 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); 274 assertThat(mCachedDevice.getConnectionSummary()).isNull(); 275 } 276 277 @Test getConnectionSummary_shortSummary_returnShortSummary()278 public void getConnectionSummary_shortSummary_returnShortSummary() { 279 // Test without battery level 280 // Set A2DP profile to be connected and test connection state summary 281 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); 282 assertThat(mCachedDevice.getConnectionSummary(true /* shortSummary */)).isNull(); 283 284 // Set device as Active for A2DP and test connection state summary 285 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); 286 assertThat(mCachedDevice.getConnectionSummary(true /* shortSummary */)).isEqualTo("Active"); 287 288 // Test with battery level 289 mBatteryLevel = 10; 290 assertThat(mCachedDevice.getConnectionSummary(true /* shortSummary */)).isEqualTo( 291 "Active"); 292 293 // Set A2DP profile to be disconnected and test connection state summary 294 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); 295 assertThat(mCachedDevice.getConnectionSummary()).isNull(); 296 } 297 298 @Test getConnectionSummary_testA2dpBatteryInactive_returnBattery()299 public void getConnectionSummary_testA2dpBatteryInactive_returnBattery() { 300 // Arrange: 301 // 1. Profile: {A2DP, CONNECTED, Inactive} 302 // 2. Battery Level: 10 303 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); 304 mBatteryLevel = 10; 305 306 // Act & Assert: 307 // Get "10% battery" result without Battery Level. 308 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("10% battery"); 309 } 310 311 @Test getConnectionSummary_testA2dpInCall_returnNull()312 public void getConnectionSummary_testA2dpInCall_returnNull() { 313 // Arrange: 314 // 1. Profile: {A2DP, Connected, Active} 315 // 2. Audio Manager: In Call 316 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); 317 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); 318 mAudioManager.setMode(AudioManager.MODE_IN_CALL); 319 320 // Act & Assert: 321 // Get null result without Battery Level. 322 assertThat(mCachedDevice.getConnectionSummary()).isNull(); 323 } 324 325 @Test getConnectionSummary_testA2dpBatteryInCall_returnBattery()326 public void getConnectionSummary_testA2dpBatteryInCall_returnBattery() { 327 // Arrange: 328 // 1. Profile: {A2DP, Connected, Active} 329 // 3. Battery Level: 10 330 // 2. Audio Manager: In Call 331 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); 332 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); 333 mBatteryLevel = 10; 334 mAudioManager.setMode(AudioManager.MODE_IN_CALL); 335 336 // Act & Assert: 337 // Get "10% battery" result with Battery Level 10. 338 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("10% battery"); 339 } 340 341 @Test getConnectionSummary_testSingleProfileActiveDeviceHfp()342 public void getConnectionSummary_testSingleProfileActiveDeviceHfp() { 343 // Test without battery level 344 // Set HFP profile to be connected and test connection state summary 345 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); 346 assertThat(mCachedDevice.getConnectionSummary()).isNull(); 347 348 // Set device as Active for HFP and test connection state summary 349 mCachedDevice.onAudioModeChanged(); 350 mAudioManager.setMode(AudioManager.MODE_IN_CALL); 351 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET); 352 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active"); 353 354 // Test with battery level 355 mBatteryLevel = 10; 356 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active, 10% battery"); 357 358 // Set HFP profile to be disconnected and test connection state summary 359 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); 360 assertThat(mCachedDevice.getConnectionSummary()).isNull(); 361 362 // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level 363 mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; 364 // Set HFP profile to be connected, Active and test connection state summary 365 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); 366 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET); 367 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active"); 368 369 // Set HFP profile to be disconnected and test connection state summary 370 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); 371 assertThat(mCachedDevice.getConnectionSummary()).isNull(); 372 } 373 374 @Test getConnectionSummary_testHeadsetBatteryInactive_returnBattery()375 public void getConnectionSummary_testHeadsetBatteryInactive_returnBattery() { 376 // Arrange: 377 // 1. Profile: {HEADSET, CONNECTED, Inactive} 378 // 2. Battery Level: 10 379 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); 380 mBatteryLevel = 10; 381 382 // Act & Assert: 383 // Get "10% battery" result without Battery Level. 384 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("10% battery"); 385 } 386 387 @Test getConnectionSummary_testHeadsetWithoutInCall_returnNull()388 public void getConnectionSummary_testHeadsetWithoutInCall_returnNull() { 389 // Arrange: 390 // 1. Profile: {HEADSET, Connected, Active} 391 // 2. Audio Manager: Normal (Without In Call) 392 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); 393 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET); 394 395 // Act & Assert: 396 // Get null result without Battery Level. 397 assertThat(mCachedDevice.getConnectionSummary()).isNull(); 398 } 399 400 @Test getConnectionSummary_testHeadsetBatteryWithoutInCall_returnBattery()401 public void getConnectionSummary_testHeadsetBatteryWithoutInCall_returnBattery() { 402 // Arrange: 403 // 1. Profile: {HEADSET, Connected, Active} 404 // 2. Battery Level: 10 405 // 3. Audio Manager: Normal (Without In Call) 406 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); 407 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET); 408 mBatteryLevel = 10; 409 410 // Act & Assert: 411 // Get "10% battery" result with Battery Level 10. 412 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("10% battery"); 413 } 414 415 @Test getConnectionSummary_testSingleProfileActiveDeviceHearingAid()416 public void getConnectionSummary_testSingleProfileActiveDeviceHearingAid() { 417 // Test without battery level 418 // Set Hearing Aid profile to be connected and test connection state summary 419 updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); 420 assertThat(mCachedDevice.getConnectionSummary()).isNull(); 421 422 // Set device as Active for Hearing Aid and test connection state summary 423 mCachedDevice.setHearingAidInfo(getLeftAshaHearingAidInfo()); 424 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID); 425 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active, left only"); 426 427 // Set Hearing Aid profile to be disconnected and test connection state summary 428 mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.HEARING_AID); 429 mCachedDevice. 430 onProfileStateChanged(mHearingAidProfile, BluetoothProfile.STATE_DISCONNECTED); 431 assertThat(mCachedDevice.getConnectionSummary()).isNull(); 432 } 433 434 @Test getConnectionSummary_testHearingAidBatteryInactive_returnBattery()435 public void getConnectionSummary_testHearingAidBatteryInactive_returnBattery() { 436 // Arrange: 437 // 1. Profile: {HEARING_AID, CONNECTED, Inactive} 438 // 2. Battery Level: 10 439 updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); 440 mBatteryLevel = 10; 441 442 // Act & Assert: 443 // Get "10% battery" result without Battery Level. 444 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("10% battery"); 445 } 446 447 @Test getConnectionSummary_testHearingAidBatteryWithoutInCall_returnActiveBattery()448 public void getConnectionSummary_testHearingAidBatteryWithoutInCall_returnActiveBattery() { 449 // Arrange: 450 // 1. Profile: {HEARING_AID, Connected, Active} 451 // 2. Battery Level: 10 452 // 3. Audio Manager: Normal (Without In Call) 453 updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); 454 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID); 455 mBatteryLevel = 10; 456 457 // Act & Assert: 458 // Get "Active, 10% battery" result with Battery Level 10. 459 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active, 10% battery"); 460 } 461 462 @Test getConnectionSummary_testHearingAidRightEarInCall_returnActiveRightEar()463 public void getConnectionSummary_testHearingAidRightEarInCall_returnActiveRightEar() { 464 // Arrange: 465 // 1. Profile: {HEARING_AID, Connected, Active, Right ear} 466 // 2. Audio Manager: In Call 467 updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); 468 mCachedDevice.setHearingAidInfo(getRightAshaHearingAidInfo()); 469 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID); 470 mAudioManager.setMode(AudioManager.MODE_IN_CALL); 471 472 // Act & Assert: 473 // Get "Active" result without Battery Level. 474 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active, right only"); 475 } 476 477 @Test getConnectionSummary_testHearingAidBothEarInCall_returnActiveBothEar()478 public void getConnectionSummary_testHearingAidBothEarInCall_returnActiveBothEar() { 479 // Arrange: 480 // 1. Profile: {HEARING_AID, Connected, Active, Both ear} 481 // 2. Audio Manager: In Call 482 mCachedDevice.setHearingAidInfo(getRightAshaHearingAidInfo()); 483 updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); 484 mSubCachedDevice.setHearingAidInfo(getLeftAshaHearingAidInfo()); 485 updateSubDeviceProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); 486 mCachedDevice.setSubDevice(mSubCachedDevice); 487 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID); 488 mAudioManager.setMode(AudioManager.MODE_IN_CALL); 489 490 // Act & Assert: 491 // Get "Active" result without Battery Level. 492 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active, left and right"); 493 } 494 495 @Test getConnectionSummary_testHearingAidBatteryInCall_returnActiveBattery()496 public void getConnectionSummary_testHearingAidBatteryInCall_returnActiveBattery() { 497 // Arrange: 498 // 1. Profile: {HEARING_AID, Connected, Active} 499 // 2. Battery Level: 10 500 // 3. Audio Manager: In Call 501 updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); 502 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID); 503 mAudioManager.setMode(AudioManager.MODE_IN_CALL); 504 mBatteryLevel = 10; 505 506 // Act & Assert: 507 // Get "Active, 10% battery" result with Battery Level 10. 508 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active, 10% battery"); 509 } 510 511 @Test getConnectionSummary_testActiveDeviceLeAudioHearingAid()512 public void getConnectionSummary_testActiveDeviceLeAudioHearingAid() { 513 // Test without battery level 514 // Set HAP Client and LE Audio profile to be connected and test connection state summary 515 when(mProfileManager.getHapClientProfile()).thenReturn(mHapClientProfile); 516 updateProfileStatus(mHapClientProfile, BluetoothProfile.STATE_CONNECTED); 517 updateProfileStatus(mLeAudioProfile, BluetoothProfile.STATE_CONNECTED); 518 assertThat(mCachedDevice.getConnectionSummary()).isNull(); 519 520 // Set device as Active for LE Audio and test connection state summary 521 mCachedDevice.setHearingAidInfo(getLeftLeAudioHearingAidInfo()); 522 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.LE_AUDIO); 523 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active, left only"); 524 525 // Set LE Audio profile to be disconnected and test connection state summary 526 mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.LE_AUDIO); 527 mCachedDevice.onProfileStateChanged(mLeAudioProfile, BluetoothProfile.STATE_DISCONNECTED); 528 assertThat(mCachedDevice.getConnectionSummary()).isNull(); 529 } 530 531 @Test getConnectionSummary_testMemberDevicesExist_returnMinBattery()532 public void getConnectionSummary_testMemberDevicesExist_returnMinBattery() { 533 // One device is active with battery level 70. 534 mBatteryLevel = 70; 535 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); 536 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); 537 538 539 // Add a member device with battery level 30. 540 int lowerBatteryLevel = 30; 541 mCachedDevice.addMemberDevice(mSubCachedDevice); 542 doAnswer((invocation) -> lowerBatteryLevel).when(mSubCachedDevice).getBatteryLevel(); 543 544 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active, 30% battery"); 545 } 546 547 @Test getConnectionSummary_testMemberDevicesBatteryUnknown_returnMinBattery()548 public void getConnectionSummary_testMemberDevicesBatteryUnknown_returnMinBattery() { 549 // One device is active with battery level 70. 550 mBatteryLevel = 70; 551 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); 552 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); 553 554 // Add a member device with battery level unknown. 555 mCachedDevice.addMemberDevice(mSubCachedDevice); 556 doAnswer((invocation) -> BluetoothDevice.BATTERY_LEVEL_UNKNOWN).when( 557 mSubCachedDevice).getBatteryLevel(); 558 559 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active, 70% battery"); 560 } 561 562 @Test getConnectionSummary_testAllDevicesBatteryUnknown_returnNoBattery()563 public void getConnectionSummary_testAllDevicesBatteryUnknown_returnNoBattery() { 564 // One device is active with battery level unknown. 565 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); 566 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); 567 568 // Add a member device with battery level unknown. 569 mCachedDevice.addMemberDevice(mSubCachedDevice); 570 doAnswer((invocation) -> BluetoothDevice.BATTERY_LEVEL_UNKNOWN).when( 571 mSubCachedDevice).getBatteryLevel(); 572 573 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active"); 574 } 575 576 @Test getConnectionSummary_testMultipleProfilesActiveDevice()577 public void getConnectionSummary_testMultipleProfilesActiveDevice() { 578 // Test without battery level 579 // Set A2DP and HFP profiles to be connected and test connection state summary 580 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); 581 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); 582 assertThat(mCachedDevice.getConnectionSummary()).isNull(); 583 584 // Set device as Active for A2DP and HFP and test connection state summary 585 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); 586 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET); 587 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active"); 588 589 // Test with battery level 590 mBatteryLevel = 10; 591 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo( 592 "Active, 10% battery"); 593 594 // Disconnect A2DP only and test connection state summary 595 mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.A2DP); 596 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); 597 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo( 598 "10% battery"); 599 600 // Disconnect HFP only and test connection state summary 601 mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.HEADSET); 602 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); 603 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); 604 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); 605 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo( 606 "Active, 10% battery"); 607 608 // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level 609 mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; 610 // Set A2DP and HFP profiles to be connected, Active and test connection state summary 611 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); 612 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); 613 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); 614 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET); 615 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active"); 616 617 // Set A2DP and HFP profiles to be disconnected and test connection state summary 618 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); 619 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); 620 assertThat(mCachedDevice.getConnectionSummary()).isNull(); 621 } 622 623 @Test getConnectionSummary_testMultipleProfilesInactive_returnPairing()624 public void getConnectionSummary_testMultipleProfilesInactive_returnPairing() { 625 // Arrange: 626 // 1. Profile 1: {A2DP, CONNECTED, Inactive} 627 // 2. Profile 2: {HEADSET, CONNECTED, Inactive} 628 // 3. Profile 3: {HEARING_AID, CONNECTED, Inactive} 629 // 4. Bond State: Bonding 630 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); 631 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); 632 updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); 633 when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDING); 634 635 // Act & Assert: 636 // Get "Pairing…" result without Battery Level. 637 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Pairing…"); 638 } 639 640 @Test getConnectionSummary_trueWirelessActiveDeviceWithBattery_returnActiveWithBattery()641 public void getConnectionSummary_trueWirelessActiveDeviceWithBattery_returnActiveWithBattery() { 642 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); 643 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); 644 updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); 645 when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); 646 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID); 647 when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn( 648 "true".getBytes()); 649 when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY)).thenReturn( 650 TWS_BATTERY_LEFT.getBytes()); 651 when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTETHERED_RIGHT_BATTERY)).thenReturn( 652 TWS_BATTERY_RIGHT.getBytes()); 653 654 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo( 655 "Active, L: 15% battery, R: 25% battery"); 656 } 657 658 @Test getConnectionSummary_trueWirelessDeviceWithBattery_returnActiveWithBattery()659 public void getConnectionSummary_trueWirelessDeviceWithBattery_returnActiveWithBattery() { 660 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); 661 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); 662 updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); 663 when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); 664 when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn( 665 "true".getBytes()); 666 when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY)).thenReturn( 667 TWS_BATTERY_LEFT.getBytes()); 668 when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTETHERED_RIGHT_BATTERY)).thenReturn( 669 TWS_BATTERY_RIGHT.getBytes()); 670 671 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo( 672 "L: 15% battery, R: 25% battery"); 673 } 674 675 @Test getCarConnectionSummary_singleProfileConnectDisconnect()676 public void getCarConnectionSummary_singleProfileConnectDisconnect() { 677 // Test without battery level 678 // Set PAN profile to be connected and test connection state summary 679 updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED); 680 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected"); 681 682 // Set PAN profile to be disconnected and test connection state summary 683 updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); 684 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected"); 685 686 // Test with battery level 687 mBatteryLevel = 10; 688 // Set PAN profile to be connected and test connection state summary 689 updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED); 690 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected, battery 10%"); 691 692 // Set PAN profile to be disconnected and test connection state summary 693 updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); 694 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected"); 695 696 // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level 697 mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; 698 699 // Set PAN profile to be connected and test connection state summary 700 updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED); 701 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected"); 702 703 // Set PAN profile to be disconnected and test connection state summary 704 updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); 705 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected"); 706 } 707 708 @Test getCarConnectionSummary_multipleProfileConnectDisconnect()709 public void getCarConnectionSummary_multipleProfileConnectDisconnect() { 710 mBatteryLevel = 10; 711 712 // Set HFP, A2DP and PAN profile to be connected and test connection state summary 713 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); 714 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); 715 updateProfileStatus(mPanProfile, BluetoothProfile.STATE_CONNECTED); 716 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected, battery 10%"); 717 718 // Disconnect HFP only and test connection state summary 719 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); 720 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo( 721 "Connected (no phone), battery 10%"); 722 723 // Disconnect A2DP only and test connection state summary 724 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); 725 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); 726 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo( 727 "Connected (no media), battery 10%"); 728 729 // Disconnect both HFP and A2DP and test connection state summary 730 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); 731 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo( 732 "Connected (no phone or media), battery 10%"); 733 734 // Disconnect all profiles and test connection state summary 735 updateProfileStatus(mPanProfile, BluetoothProfile.STATE_DISCONNECTED); 736 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected"); 737 } 738 739 @Test getCarConnectionSummary_singleProfileActiveDeviceA2dp()740 public void getCarConnectionSummary_singleProfileActiveDeviceA2dp() { 741 // Test without battery level 742 // Set A2DP profile to be connected and test connection state summary 743 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); 744 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected"); 745 746 // Set device as Active for A2DP and test connection state summary 747 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); 748 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected, active (media)"); 749 750 // Test with battery level 751 mBatteryLevel = 10; 752 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo( 753 "Connected, battery 10%, active (media)"); 754 755 // Set A2DP profile to be disconnected and test connection state summary 756 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); 757 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected"); 758 759 // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level 760 mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; 761 // Set A2DP profile to be connected, Active and test connection state summary 762 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); 763 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); 764 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected, active (media)"); 765 766 // Set A2DP profile to be disconnected and test connection state summary 767 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); 768 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected"); 769 } 770 771 @Test getCarConnectionSummary_singleProfileActiveDeviceHfp()772 public void getCarConnectionSummary_singleProfileActiveDeviceHfp() { 773 // Test without battery level 774 // Set HFP profile to be connected and test connection state summary 775 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); 776 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected"); 777 778 // Set device as Active for HFP and test connection state summary 779 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET); 780 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected, active (phone)"); 781 782 // Test with battery level 783 mBatteryLevel = 10; 784 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo( 785 "Connected, battery 10%, active (phone)"); 786 787 // Set HFP profile to be disconnected and test connection state summary 788 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); 789 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected"); 790 791 // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level 792 mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; 793 // Set HFP profile to be connected, Active and test connection state summary 794 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); 795 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET); 796 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected, active (phone)"); 797 798 // Set HFP profile to be disconnected and test connection state summary 799 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); 800 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected"); 801 } 802 803 @Test getCarConnectionSummary_singleProfileActiveDeviceHearingAid()804 public void getCarConnectionSummary_singleProfileActiveDeviceHearingAid() { 805 // Test without battery level 806 // Set Hearing Aid profile to be connected and test connection state summary 807 updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); 808 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected"); 809 810 // Set device as Active for Hearing Aid and test connection state summary 811 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID); 812 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected, active"); 813 814 // Set Hearing Aid profile to be disconnected and test connection state summary 815 mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.HEARING_AID); 816 updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_DISCONNECTED); 817 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected"); 818 } 819 820 @Test getCarConnectionSummary_multipleProfilesActiveDevice()821 public void getCarConnectionSummary_multipleProfilesActiveDevice() { 822 // Test without battery level 823 // Set A2DP and HFP profiles to be connected and test connection state summary 824 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); 825 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); 826 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected"); 827 828 // Set device as Active for A2DP and HFP and test connection state summary 829 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); 830 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET); 831 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected, active"); 832 833 // Test with battery level 834 mBatteryLevel = 10; 835 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo( 836 "Connected, battery 10%, active"); 837 838 // Disconnect A2DP only and test connection state summary 839 mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.A2DP); 840 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); 841 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo( 842 "Connected (no media), battery 10%, active (phone)"); 843 844 // Disconnect HFP only and test connection state summary 845 mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.HEADSET); 846 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); 847 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); 848 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); 849 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo( 850 "Connected (no phone), battery 10%, active (media)"); 851 852 // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level 853 mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; 854 // Set A2DP and HFP profiles to be connected, Active and test connection state summary 855 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); 856 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); 857 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); 858 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEADSET); 859 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Connected, active"); 860 861 // Set A2DP and HFP profiles to be disconnected and test connection state summary 862 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); 863 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); 864 assertThat(mCachedDevice.getCarConnectionSummary()).isEqualTo("Disconnected"); 865 } 866 867 @Test getCarConnectionSummary_shortSummary_returnShortSummary()868 public void getCarConnectionSummary_shortSummary_returnShortSummary() { 869 // Test without battery level 870 // Set A2DP profile to be connected and test connection state summary 871 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); 872 assertThat(mCachedDevice.getCarConnectionSummary(true /* shortSummary */)) 873 .isEqualTo("Connected"); 874 875 // Set device as Active for A2DP and test connection state summary 876 mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); 877 assertThat(mCachedDevice.getCarConnectionSummary(true /* shortSummary */)) 878 .isEqualTo("Connected"); 879 880 // Test with battery level 881 mBatteryLevel = 10; 882 assertThat(mCachedDevice.getCarConnectionSummary(true /* shortSummary */)) 883 .isEqualTo("Connected"); 884 885 // Set A2DP profile to be disconnected and test connection state summary 886 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); 887 assertThat(mCachedDevice.getCarConnectionSummary(true /* shortSummary */)) 888 .isEqualTo("Disconnected"); 889 } 890 891 @Test deviceName_testAliasNameAvailable()892 public void deviceName_testAliasNameAvailable() { 893 when(mDevice.getAlias()).thenReturn(DEVICE_ALIAS); 894 when(mDevice.getName()).thenReturn(DEVICE_NAME); 895 CachedBluetoothDevice cachedBluetoothDevice = 896 new CachedBluetoothDevice(mContext, mProfileManager, mDevice); 897 // Verify alias is returned on getName 898 assertThat(cachedBluetoothDevice.getName()).isEqualTo(DEVICE_ALIAS); 899 // Verify device is visible 900 assertThat(cachedBluetoothDevice.hasHumanReadableName()).isTrue(); 901 } 902 903 @Test deviceName_testNameNotAvailable()904 public void deviceName_testNameNotAvailable() { 905 CachedBluetoothDevice cachedBluetoothDevice = 906 new CachedBluetoothDevice(mContext, mProfileManager, mDevice); 907 // Verify device address is returned on getName 908 assertThat(cachedBluetoothDevice.getName()).isEqualTo(DEVICE_ADDRESS); 909 // Verify device is not visible 910 assertThat(cachedBluetoothDevice.hasHumanReadableName()).isFalse(); 911 } 912 913 @Test deviceName_testRenameDevice()914 public void deviceName_testRenameDevice() { 915 final String[] alias = {DEVICE_ALIAS}; 916 doAnswer(invocation -> alias[0]).when(mDevice).getAlias(); 917 doAnswer(invocation -> { 918 alias[0] = (String) invocation.getArguments()[0]; 919 return BluetoothStatusCodes.SUCCESS; 920 }).when(mDevice).setAlias(anyString()); 921 when(mDevice.getName()).thenReturn(DEVICE_NAME); 922 CachedBluetoothDevice cachedBluetoothDevice = 923 new CachedBluetoothDevice(mContext, mProfileManager, mDevice); 924 // Verify alias is returned on getName 925 assertThat(cachedBluetoothDevice.getName()).isEqualTo(DEVICE_ALIAS); 926 // Verify null name does not get set 927 cachedBluetoothDevice.setName(null); 928 verify(mDevice, never()).setAlias(any()); 929 // Verify new name is set properly 930 cachedBluetoothDevice.setName(DEVICE_ALIAS_NEW); 931 verify(mDevice).setAlias(DEVICE_ALIAS_NEW); 932 // Verify new alias is returned on getName 933 assertThat(cachedBluetoothDevice.getName()).isEqualTo(DEVICE_ALIAS_NEW); 934 } 935 936 @Test setActive()937 public void setActive() { 938 when(mProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile); 939 when(mProfileManager.getHeadsetProfile()).thenReturn(mHfpProfile); 940 when(mA2dpProfile.setActiveDevice(any(BluetoothDevice.class))).thenReturn(true); 941 when(mHfpProfile.setActiveDevice(any(BluetoothDevice.class))).thenReturn(true); 942 943 assertThat(mCachedDevice.setActive()).isFalse(); 944 945 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED); 946 assertThat(mCachedDevice.setActive()).isTrue(); 947 948 updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED); 949 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); 950 assertThat(mCachedDevice.setActive()).isTrue(); 951 952 updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED); 953 assertThat(mCachedDevice.setActive()).isFalse(); 954 } 955 956 @Test isA2dpDevice_isA2dpDevice()957 public void isA2dpDevice_isA2dpDevice() { 958 when(mProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile); 959 when(mA2dpProfile.getConnectionStatus(mDevice)). 960 thenReturn(BluetoothProfile.STATE_CONNECTED); 961 962 assertThat(mCachedDevice.isConnectedA2dpDevice()).isTrue(); 963 } 964 965 @Test isA2dpDevice_isNotA2dpDevice()966 public void isA2dpDevice_isNotA2dpDevice() { 967 when(mProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile); 968 when(mA2dpProfile.getConnectionStatus(mDevice)). 969 thenReturn(BluetoothProfile.STATE_DISCONNECTING); 970 971 assertThat(mCachedDevice.isConnectedA2dpDevice()).isFalse(); 972 } 973 974 @Test isHfpDevice_isHfpDevice()975 public void isHfpDevice_isHfpDevice() { 976 when(mProfileManager.getHeadsetProfile()).thenReturn(mHfpProfile); 977 when(mHfpProfile.getConnectionStatus(mDevice)). 978 thenReturn(BluetoothProfile.STATE_CONNECTED); 979 980 assertThat(mCachedDevice.isConnectedHfpDevice()).isTrue(); 981 } 982 983 @Test testIsHfpDevice_isNotHfpDevice()984 public void testIsHfpDevice_isNotHfpDevice() { 985 when(mProfileManager.getHeadsetProfile()).thenReturn(mHfpProfile); 986 when(mHfpProfile.getConnectionStatus(mDevice)). 987 thenReturn(BluetoothProfile.STATE_DISCONNECTING); 988 989 assertThat(mCachedDevice.isConnectedHfpDevice()).isFalse(); 990 } 991 992 @Test isConnectedAshaHearingAidDevice_connected_returnTrue()993 public void isConnectedAshaHearingAidDevice_connected_returnTrue() { 994 when(mProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile); 995 when(mHearingAidProfile.getConnectionStatus(mDevice)). 996 thenReturn(BluetoothProfile.STATE_CONNECTED); 997 998 assertThat(mCachedDevice.isConnectedAshaHearingAidDevice()).isTrue(); 999 } 1000 1001 @Test isConnectedAshaHearingAidDevice_disconnected_returnFalse()1002 public void isConnectedAshaHearingAidDevice_disconnected_returnFalse() { 1003 when(mProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile); 1004 when(mHearingAidProfile.getConnectionStatus(mDevice)). 1005 thenReturn(BluetoothProfile.STATE_DISCONNECTED); 1006 1007 assertThat(mCachedDevice.isConnectedAshaHearingAidDevice()).isFalse(); 1008 } 1009 1010 @Test isConnectedHfpDevice_profileIsNull_returnFalse()1011 public void isConnectedHfpDevice_profileIsNull_returnFalse() { 1012 when(mProfileManager.getHeadsetProfile()).thenReturn(null); 1013 1014 assertThat(mCachedDevice.isConnectedHfpDevice()).isFalse(); 1015 } 1016 1017 @Test isConnectedA2dpDevice_profileIsNull_returnFalse()1018 public void isConnectedA2dpDevice_profileIsNull_returnFalse() { 1019 when(mProfileManager.getA2dpProfile()).thenReturn(null); 1020 1021 assertThat(mCachedDevice.isConnectedA2dpDevice()).isFalse(); 1022 } 1023 1024 @Test isConnectedAshaHearingAidDevice_profileIsNull_returnFalse()1025 public void isConnectedAshaHearingAidDevice_profileIsNull_returnFalse() { 1026 when(mProfileManager.getHearingAidProfile()).thenReturn(null); 1027 1028 assertThat(mCachedDevice.isConnectedAshaHearingAidDevice()).isFalse(); 1029 } 1030 1031 @Test getName_aliasNameNotNull_returnAliasName()1032 public void getName_aliasNameNotNull_returnAliasName() { 1033 when(mDevice.getAlias()).thenReturn(DEVICE_NAME); 1034 1035 assertThat(mCachedDevice.getName()).isEqualTo(DEVICE_NAME); 1036 } 1037 1038 @Test getName_aliasNameIsNull_returnAddress()1039 public void getName_aliasNameIsNull_returnAddress() { 1040 when(mDevice.getAlias()).thenReturn(null); 1041 1042 assertThat(mCachedDevice.getName()).isEqualTo(DEVICE_ADDRESS); 1043 } 1044 1045 @Test setName_setDeviceNameIsNotNull()1046 public void setName_setDeviceNameIsNotNull() { 1047 final String name = "test name"; 1048 when(mDevice.getAlias()).thenReturn(DEVICE_NAME); 1049 1050 mCachedDevice.setName(name); 1051 1052 verify(mDevice).setAlias(name); 1053 } 1054 1055 @Test setName_setDeviceNameIsNull()1056 public void setName_setDeviceNameIsNull() { 1057 mCachedDevice.setName(null); 1058 1059 verify(mDevice, never()).setAlias(any()); 1060 } 1061 1062 @Test setName_setDeviceNameIsEmpty()1063 public void setName_setDeviceNameIsEmpty() { 1064 mCachedDevice.setName(""); 1065 1066 verify(mDevice, never()).setAlias(any()); 1067 } 1068 1069 @Test getProfileConnectionState_nullProfile_returnDisconnected()1070 public void getProfileConnectionState_nullProfile_returnDisconnected() { 1071 assertThat(mCachedDevice.getProfileConnectionState(null)).isEqualTo( 1072 BluetoothProfile.STATE_DISCONNECTED); 1073 } 1074 1075 @Test getProfileConnectionState_profileConnected_returnConnected()1076 public void getProfileConnectionState_profileConnected_returnConnected() { 1077 doReturn(BluetoothProfile.STATE_CONNECTED).when(mA2dpProfile).getConnectionStatus( 1078 any(BluetoothDevice.class)); 1079 1080 assertThat(mCachedDevice.getProfileConnectionState(mA2dpProfile)).isEqualTo( 1081 BluetoothProfile.STATE_CONNECTED); 1082 } 1083 updateProfileStatus(LocalBluetoothProfile profile, int status)1084 private void updateProfileStatus(LocalBluetoothProfile profile, int status) { 1085 doReturn(status).when(profile).getConnectionStatus(mDevice); 1086 mCachedDevice.onProfileStateChanged(profile, status); 1087 } 1088 updateSubDeviceProfileStatus(LocalBluetoothProfile profile, int status)1089 private void updateSubDeviceProfileStatus(LocalBluetoothProfile profile, int status) { 1090 doReturn(status).when(profile).getConnectionStatus(mSubDevice); 1091 mSubCachedDevice.onProfileStateChanged(profile, status); 1092 } 1093 1094 @Test getSubDevice_setSubDevice()1095 public void getSubDevice_setSubDevice() { 1096 mCachedDevice.setSubDevice(mSubCachedDevice); 1097 1098 assertThat(mCachedDevice.getSubDevice()).isEqualTo(mSubCachedDevice); 1099 } 1100 1101 @Test switchSubDeviceContent()1102 public void switchSubDeviceContent() { 1103 1104 mCachedDevice.mRssi = RSSI_1; 1105 mCachedDevice.mJustDiscovered = JUSTDISCOVERED_1; 1106 mCachedDevice.setHearingAidInfo(getLeftAshaHearingAidInfo()); 1107 mSubCachedDevice.mRssi = RSSI_2; 1108 mSubCachedDevice.mJustDiscovered = JUSTDISCOVERED_2; 1109 mSubCachedDevice.setHearingAidInfo(getRightAshaHearingAidInfo()); 1110 mCachedDevice.setSubDevice(mSubCachedDevice); 1111 1112 mCachedDevice.switchSubDeviceContent(); 1113 1114 verify(mCachedDevice).release(); 1115 assertThat(mCachedDevice.mRssi).isEqualTo(RSSI_2); 1116 assertThat(mCachedDevice.mJustDiscovered).isEqualTo(JUSTDISCOVERED_2); 1117 assertThat(mCachedDevice.mDevice).isEqualTo(mSubDevice); 1118 assertThat(mCachedDevice.getDeviceSide()).isEqualTo(HearingAidInfo.DeviceSide.SIDE_RIGHT); 1119 verify(mSubCachedDevice).release(); 1120 assertThat(mSubCachedDevice.mRssi).isEqualTo(RSSI_1); 1121 assertThat(mSubCachedDevice.mJustDiscovered).isEqualTo(JUSTDISCOVERED_1); 1122 assertThat(mSubCachedDevice.mDevice).isEqualTo(mDevice); 1123 assertThat(mSubCachedDevice.getDeviceSide()).isEqualTo(HearingAidInfo.DeviceSide.SIDE_LEFT); 1124 } 1125 1126 @Test getConnectionSummary_profileConnectedFail_showErrorMessage()1127 public void getConnectionSummary_profileConnectedFail_showErrorMessage() { 1128 final A2dpProfile profile = mock(A2dpProfile.class); 1129 mCachedDevice.onProfileStateChanged(profile, BluetoothProfile.STATE_CONNECTED); 1130 mCachedDevice.setProfileConnectedStatus(BluetoothProfile.A2DP, true); 1131 1132 when(profile.getConnectionStatus(mDevice)).thenReturn(BluetoothProfile.STATE_CONNECTED); 1133 1134 assertThat(mCachedDevice.getConnectionSummary()).isEqualTo( 1135 mContext.getString(R.string.profile_connect_timeout_subtext)); 1136 } 1137 1138 @Test onUuidChanged_bluetoothClassIsNull_shouldNotCrash()1139 public void onUuidChanged_bluetoothClassIsNull_shouldNotCrash() { 1140 mShadowBluetoothAdapter.setUuids(PbapServerProfile.PBAB_CLIENT_UUIDS); 1141 when(mDevice.getUuids()).thenReturn(PbapServerProfile.PBAB_CLIENT_UUIDS); 1142 when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); 1143 when(mDevice.getPhonebookAccessPermission()).thenReturn(BluetoothDevice.ACCESS_UNKNOWN); 1144 when(mDevice.getBluetoothClass()).thenReturn(null); 1145 1146 mCachedDevice.onUuidChanged(); 1147 1148 // Should not crash 1149 } 1150 1151 @Test getDrawableWithDescription_isAdvancedDevice_returnAdvancedIcon()1152 public void getDrawableWithDescription_isAdvancedDevice_returnAdvancedIcon() { 1153 LruCache lruCache = mock(LruCache.class); 1154 mCachedDevice.mDrawableCache = lruCache; 1155 BitmapDrawable drawable = mock(BitmapDrawable.class); 1156 when(lruCache.get("fake_uri")).thenReturn(drawable); 1157 when(mDevice.getMetadata(BluetoothDevice.METADATA_MAIN_ICON)) 1158 .thenReturn("fake_uri".getBytes()); 1159 when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)) 1160 .thenReturn("true".getBytes()); 1161 1162 mCachedDevice.refresh(); 1163 1164 assertThat(mCachedDevice.getDrawableWithDescription().first).isInstanceOf( 1165 AdaptiveOutlineDrawable.class); 1166 } 1167 1168 @Test getDrawableWithDescription_isNotAdvancedDevice_returnBluetoothIcon()1169 public void getDrawableWithDescription_isNotAdvancedDevice_returnBluetoothIcon() { 1170 when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)) 1171 .thenReturn("false".getBytes()); 1172 1173 mCachedDevice.refresh(); 1174 1175 assertThat(mCachedDevice.getDrawableWithDescription().first).isNotInstanceOf( 1176 AdaptiveOutlineDrawable.class); 1177 } 1178 1179 @Test releaseLruCache_lruCacheShouldBeRelease()1180 public void releaseLruCache_lruCacheShouldBeRelease() { 1181 when(mDevice.getMetadata(BluetoothDevice.METADATA_MAIN_ICON)) 1182 .thenReturn("fake_uri".getBytes()); 1183 when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)) 1184 .thenReturn("true".getBytes()); 1185 1186 mCachedDevice.refresh(); 1187 mCachedDevice.releaseLruCache(); 1188 1189 assertThat(mCachedDevice.mDrawableCache.size()).isEqualTo(0); 1190 } 1191 1192 @Test switchMemberDeviceContent_switchMainDevice_switchesSuccessful()1193 public void switchMemberDeviceContent_switchMainDevice_switchesSuccessful() { 1194 mCachedDevice.mRssi = RSSI_1; 1195 mCachedDevice.mJustDiscovered = JUSTDISCOVERED_1; 1196 mSubCachedDevice.mRssi = RSSI_2; 1197 mSubCachedDevice.mJustDiscovered = JUSTDISCOVERED_2; 1198 mCachedDevice.addMemberDevice(mSubCachedDevice); 1199 1200 mCachedDevice.switchMemberDeviceContent(mSubCachedDevice); 1201 1202 assertThat(mCachedDevice.mRssi).isEqualTo(RSSI_2); 1203 assertThat(mCachedDevice.mJustDiscovered).isEqualTo(JUSTDISCOVERED_2); 1204 assertThat(mCachedDevice.mDevice).isEqualTo(mSubDevice); 1205 verify(mCachedDevice).fillData(); 1206 assertThat(mSubCachedDevice.mRssi).isEqualTo(RSSI_1); 1207 assertThat(mSubCachedDevice.mJustDiscovered).isEqualTo(JUSTDISCOVERED_1); 1208 assertThat(mSubCachedDevice.mDevice).isEqualTo(mDevice); 1209 verify(mSubCachedDevice).fillData(); 1210 assertThat(mCachedDevice.getMemberDevice().contains(mSubCachedDevice)).isTrue(); 1211 } 1212 1213 @Test isConnectedHearingAidDevice_isConnectedAshaHearingAidDevice_returnTrue()1214 public void isConnectedHearingAidDevice_isConnectedAshaHearingAidDevice_returnTrue() { 1215 when(mProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile); 1216 1217 updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); 1218 1219 assertThat(mCachedDevice.isConnectedHearingAidDevice()).isTrue(); 1220 } 1221 1222 @Test isConnectedHearingAidDevice_isConnectedLeAudioHearingAidDevice_returnTrue()1223 public void isConnectedHearingAidDevice_isConnectedLeAudioHearingAidDevice_returnTrue() { 1224 when(mProfileManager.getHapClientProfile()).thenReturn(mHapClientProfile); 1225 when(mProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile); 1226 1227 updateProfileStatus(mHapClientProfile, BluetoothProfile.STATE_CONNECTED); 1228 updateProfileStatus(mLeAudioProfile, BluetoothProfile.STATE_CONNECTED); 1229 1230 assertThat(mCachedDevice.isConnectedHearingAidDevice()).isTrue(); 1231 } 1232 1233 @Test isConnectedHearingAidDevice_isNotAnyConnectedHearingAidDevice_returnFalse()1234 public void isConnectedHearingAidDevice_isNotAnyConnectedHearingAidDevice_returnFalse() { 1235 when(mProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile); 1236 when(mProfileManager.getHapClientProfile()).thenReturn(mHapClientProfile); 1237 when(mProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile); 1238 1239 updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_DISCONNECTED); 1240 updateProfileStatus(mHapClientProfile, BluetoothProfile.STATE_DISCONNECTED); 1241 updateProfileStatus(mLeAudioProfile, BluetoothProfile.STATE_DISCONNECTED); 1242 1243 assertThat(mCachedDevice.isConnectedHearingAidDevice()).isFalse(); 1244 } 1245 getLeftAshaHearingAidInfo()1246 private HearingAidInfo getLeftAshaHearingAidInfo() { 1247 return new HearingAidInfo.Builder() 1248 .setAshaDeviceSide(HearingAidProfile.DeviceSide.SIDE_LEFT) 1249 .build(); 1250 } 1251 getRightAshaHearingAidInfo()1252 private HearingAidInfo getRightAshaHearingAidInfo() { 1253 return new HearingAidInfo.Builder() 1254 .setAshaDeviceSide(HearingAidProfile.DeviceSide.SIDE_RIGHT) 1255 .build(); 1256 } 1257 getLeftLeAudioHearingAidInfo()1258 private HearingAidInfo getLeftLeAudioHearingAidInfo() { 1259 return new HearingAidInfo.Builder() 1260 .setLeAudioLocation(BluetoothLeAudio.AUDIO_LOCATION_SIDE_LEFT) 1261 .build(); 1262 } 1263 } 1264