1 /* 2 * Copyright (C) 2019 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 com.google.common.truth.Truth.assertThat; 20 21 import static org.mockito.Mockito.never; 22 import static org.mockito.Mockito.verify; 23 import static org.mockito.Mockito.when; 24 import static org.robolectric.Shadows.shadowOf; 25 26 import android.bluetooth.BluetoothAdapter; 27 import android.bluetooth.BluetoothDevice; 28 import android.content.Context; 29 import android.graphics.Bitmap; 30 import android.graphics.drawable.Drawable; 31 import android.provider.DeviceConfig; 32 import android.view.LayoutInflater; 33 import android.view.View; 34 import android.widget.ImageView; 35 import android.widget.LinearLayout; 36 import android.widget.TextView; 37 38 import com.android.settings.R; 39 import com.android.settings.core.BasePreferenceController; 40 import com.android.settings.core.SettingsUIDeviceConfig; 41 import com.android.settings.fuelgauge.BatteryMeterView; 42 import com.android.settings.testutils.shadow.ShadowDeviceConfig; 43 import com.android.settings.testutils.shadow.ShadowEntityHeaderController; 44 import com.android.settingslib.bluetooth.BluetoothUtils; 45 import com.android.settingslib.bluetooth.CachedBluetoothDevice; 46 import com.android.settingslib.utils.StringUtil; 47 import com.android.settingslib.widget.LayoutPreference; 48 49 import org.junit.Before; 50 import org.junit.Ignore; 51 import org.junit.Test; 52 import org.junit.runner.RunWith; 53 import org.mockito.Mock; 54 import org.mockito.MockitoAnnotations; 55 import org.robolectric.RobolectricTestRunner; 56 import org.robolectric.RuntimeEnvironment; 57 import org.robolectric.annotation.Config; 58 59 import java.util.HashSet; 60 import java.util.Set; 61 62 @RunWith(RobolectricTestRunner.class) 63 @Config(shadows = {ShadowEntityHeaderController.class, ShadowDeviceConfig.class}) 64 public class AdvancedBluetoothDetailsHeaderControllerTest { 65 private static final int BATTERY_LEVEL_MAIN = 30; 66 private static final int BATTERY_LEVEL_LEFT = 25; 67 private static final int BATTERY_LEVEL_RIGHT = 45; 68 private static final int LOW_BATTERY_LEVEL = 15; 69 private static final int CASE_LOW_BATTERY_LEVEL = 19; 70 private static final int LOW_BATTERY_LEVEL_THRESHOLD = 15; 71 private static final int BATTERY_LEVEL_5 = 5; 72 private static final int BATTERY_LEVEL_50 = 50; 73 private static final String ICON_URI = "content://test.provider/icon.png"; 74 private static final String MAC_ADDRESS = "04:52:C7:0B:D8:3C"; 75 private static final String DEVICE_SUMMARY = "test summary"; 76 77 private Context mContext; 78 79 @Mock 80 private BluetoothDevice mBluetoothDevice; 81 @Mock 82 private Bitmap mBitmap; 83 @Mock 84 private ImageView mImageView; 85 @Mock 86 private CachedBluetoothDevice mCachedDevice; 87 @Mock 88 private BluetoothAdapter mBluetoothAdapter; 89 private AdvancedBluetoothDetailsHeaderController mController; 90 private LayoutPreference mLayoutPreference; 91 92 @Before setUp()93 public void setUp() { 94 MockitoAnnotations.initMocks(this); 95 96 mContext = RuntimeEnvironment.application; 97 mController = new AdvancedBluetoothDetailsHeaderController(mContext, "pref_Key"); 98 when(mCachedDevice.getDevice()).thenReturn(mBluetoothDevice); 99 mController.init(mCachedDevice); 100 mLayoutPreference = new LayoutPreference(mContext, 101 LayoutInflater.from(mContext).inflate(R.layout.advanced_bt_entity_header, null)); 102 mController.mLayoutPreference = mLayoutPreference; 103 mController.mBluetoothAdapter = mBluetoothAdapter; 104 when(mCachedDevice.getDevice()).thenReturn(mBluetoothDevice); 105 when(mCachedDevice.getAddress()).thenReturn(MAC_ADDRESS); 106 when(mCachedDevice.getIdentityAddress()).thenReturn(MAC_ADDRESS); 107 } 108 109 @Test createBatteryIcon_hasCorrectInfo()110 public void createBatteryIcon_hasCorrectInfo() { 111 final Drawable drawable = mController.createBtBatteryIcon(mContext, BATTERY_LEVEL_MAIN, 112 true /* charging */); 113 assertThat(drawable).isInstanceOf(BatteryMeterView.BatteryMeterDrawable.class); 114 115 final BatteryMeterView.BatteryMeterDrawable iconDrawable = 116 (BatteryMeterView.BatteryMeterDrawable) drawable; 117 assertThat(iconDrawable.getBatteryLevel()).isEqualTo(BATTERY_LEVEL_MAIN); 118 assertThat(iconDrawable.getCharging()).isTrue(); 119 } 120 121 @Test refresh_connectedWatch_behaveAsExpected()122 public void refresh_connectedWatch_behaveAsExpected() { 123 when(mBluetoothDevice.getMetadata( 124 BluetoothDevice.METADATA_DEVICE_TYPE)).thenReturn( 125 BluetoothDevice.DEVICE_TYPE_WATCH.getBytes()); 126 when(mBluetoothDevice.getMetadata( 127 BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn( 128 String.valueOf(false).getBytes()); 129 when(mCachedDevice.isConnected()).thenReturn(true); 130 131 mController.refresh(); 132 133 assertThat(mLayoutPreference.findViewById(R.id.layout_left).getVisibility()).isEqualTo( 134 View.GONE); 135 assertThat(mLayoutPreference.findViewById(R.id.layout_right).getVisibility()).isEqualTo( 136 View.GONE); 137 assertThat(mLayoutPreference.findViewById(R.id.layout_middle).getVisibility()).isEqualTo( 138 View.VISIBLE); 139 // TODO (b/188954766) : clarify settings design 140 } 141 142 @Test refresh_connectedWatch_unknownBatteryLevel_shouldNotShowBatteryLevel()143 public void refresh_connectedWatch_unknownBatteryLevel_shouldNotShowBatteryLevel() { 144 when(mBluetoothDevice.getMetadata( 145 BluetoothDevice.METADATA_DEVICE_TYPE)).thenReturn( 146 BluetoothDevice.DEVICE_TYPE_WATCH.getBytes()); 147 when(mBluetoothDevice.getMetadata( 148 BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn( 149 String.valueOf(false).getBytes()); 150 when(mBluetoothDevice.getMetadata( 151 BluetoothDevice.METADATA_MAIN_BATTERY)).thenReturn( 152 String.valueOf(BluetoothUtils.META_INT_ERROR).getBytes()); 153 when(mBluetoothDevice.getBatteryLevel()).thenReturn(BluetoothDevice.BATTERY_LEVEL_UNKNOWN); 154 when(mCachedDevice.isConnected()).thenReturn(true); 155 156 mController.refresh(); 157 158 assertThat(mLayoutPreference.findViewById(R.id.layout_left).getVisibility()).isEqualTo( 159 View.GONE); 160 assertThat(mLayoutPreference.findViewById(R.id.layout_right).getVisibility()).isEqualTo( 161 View.GONE); 162 assertThat(mLayoutPreference.findViewById(R.id.layout_middle).getVisibility()).isEqualTo( 163 View.VISIBLE); 164 assertThat(mLayoutPreference.findViewById(R.id.layout_middle) 165 .requireViewById(R.id.bt_battery_summary).getVisibility()).isEqualTo(View.GONE); 166 } 167 168 @Test refresh_connectedStylus_behaveAsExpected()169 public void refresh_connectedStylus_behaveAsExpected() { 170 when(mBluetoothDevice.getMetadata( 171 BluetoothDevice.METADATA_DEVICE_TYPE)).thenReturn( 172 BluetoothDevice.DEVICE_TYPE_STYLUS.getBytes()); 173 when(mBluetoothDevice.getMetadata( 174 BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn( 175 String.valueOf(false).getBytes()); 176 when(mCachedDevice.isConnected()).thenReturn(true); 177 178 mController.refresh(); 179 180 assertThat(mLayoutPreference.findViewById(R.id.layout_left).getVisibility()).isEqualTo( 181 View.GONE); 182 assertThat(mLayoutPreference.findViewById(R.id.layout_right).getVisibility()).isEqualTo( 183 View.GONE); 184 assertThat(mLayoutPreference.findViewById(R.id.layout_middle).getVisibility()).isEqualTo( 185 View.VISIBLE); 186 } 187 188 @Test refresh_connectedUnknownType_behaveAsExpected()189 public void refresh_connectedUnknownType_behaveAsExpected() { 190 when(mBluetoothDevice.getMetadata( 191 BluetoothDevice.METADATA_DEVICE_TYPE)).thenReturn( 192 "UNKNOWN_TYPE".getBytes()); 193 when(mBluetoothDevice.getMetadata( 194 BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn( 195 String.valueOf(false).getBytes()); 196 when(mCachedDevice.isConnected()).thenReturn(true); 197 198 mController.refresh(); 199 200 assertThat(mLayoutPreference.findViewById(R.id.layout_left).getVisibility()).isEqualTo( 201 View.GONE); 202 assertThat(mLayoutPreference.findViewById(R.id.layout_right).getVisibility()).isEqualTo( 203 View.GONE); 204 assertThat(mLayoutPreference.findViewById(R.id.layout_middle).getVisibility()).isEqualTo( 205 View.VISIBLE); 206 } 207 208 @Test refresh_connectedUntetheredHeadset_behaveAsExpected()209 public void refresh_connectedUntetheredHeadset_behaveAsExpected() { 210 when(mBluetoothDevice.getMetadata( 211 BluetoothDevice.METADATA_DEVICE_TYPE)).thenReturn( 212 BluetoothDevice.DEVICE_TYPE_UNTETHERED_HEADSET.getBytes()); 213 when(mBluetoothDevice.getMetadata( 214 BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn( 215 String.valueOf(false).getBytes()); 216 when(mBluetoothDevice.getMetadata( 217 BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY)).thenReturn( 218 String.valueOf(BATTERY_LEVEL_LEFT).getBytes()); 219 when(mBluetoothDevice.getMetadata( 220 BluetoothDevice.METADATA_UNTETHERED_RIGHT_BATTERY)).thenReturn( 221 String.valueOf(BATTERY_LEVEL_RIGHT).getBytes()); 222 when(mBluetoothDevice.getMetadata( 223 BluetoothDevice.METADATA_UNTETHERED_CASE_BATTERY)).thenReturn( 224 String.valueOf(BATTERY_LEVEL_MAIN).getBytes()); 225 when(mCachedDevice.isConnected()).thenReturn(true); 226 227 mController.refresh(); 228 229 assertBatteryLevel(mLayoutPreference.findViewById(R.id.layout_left), BATTERY_LEVEL_LEFT); 230 assertBatteryLevel(mLayoutPreference.findViewById(R.id.layout_right), BATTERY_LEVEL_RIGHT); 231 assertBatteryLevel(mLayoutPreference.findViewById(R.id.layout_middle), BATTERY_LEVEL_MAIN); 232 } 233 234 @Test refresh_connected_updateCorrectInfo()235 public void refresh_connected_updateCorrectInfo() { 236 when(mBluetoothDevice.getMetadata( 237 BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn( 238 String.valueOf(true).getBytes()); 239 when(mBluetoothDevice.getMetadata( 240 BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY)).thenReturn( 241 String.valueOf(BATTERY_LEVEL_LEFT).getBytes()); 242 when(mBluetoothDevice.getMetadata( 243 BluetoothDevice.METADATA_UNTETHERED_RIGHT_BATTERY)).thenReturn( 244 String.valueOf(BATTERY_LEVEL_RIGHT).getBytes()); 245 when(mBluetoothDevice.getMetadata( 246 BluetoothDevice.METADATA_UNTETHERED_CASE_BATTERY)).thenReturn( 247 String.valueOf(BATTERY_LEVEL_MAIN).getBytes()); 248 249 when(mCachedDevice.isConnected()).thenReturn(true); 250 mController.refresh(); 251 252 assertBatteryLevel(mLayoutPreference.findViewById(R.id.layout_left), BATTERY_LEVEL_LEFT); 253 assertBatteryLevel(mLayoutPreference.findViewById(R.id.layout_right), BATTERY_LEVEL_RIGHT); 254 assertBatteryLevel(mLayoutPreference.findViewById(R.id.layout_middle), BATTERY_LEVEL_MAIN); 255 } 256 257 @Test refresh_disconnected_updateCorrectInfo()258 public void refresh_disconnected_updateCorrectInfo() { 259 when(mCachedDevice.isConnected()).thenReturn(false); 260 261 mController.refresh(); 262 263 final LinearLayout layout = mLayoutPreference.findViewById(R.id.layout_middle); 264 265 assertThat(mLayoutPreference.findViewById(R.id.layout_left).getVisibility()).isEqualTo( 266 View.GONE); 267 assertThat(mLayoutPreference.findViewById(R.id.layout_right).getVisibility()).isEqualTo( 268 View.GONE); 269 assertThat(layout.getVisibility()).isEqualTo(View.VISIBLE); 270 assertThat(layout.findViewById(R.id.header_title).getVisibility()).isEqualTo(View.GONE); 271 assertThat(layout.findViewById(R.id.bt_battery_summary).getVisibility()).isEqualTo( 272 View.GONE); 273 assertThat(layout.findViewById(R.id.bt_battery_icon).getVisibility()).isEqualTo(View.GONE); 274 assertThat(layout.findViewById(R.id.header_icon).getVisibility()).isEqualTo(View.VISIBLE); 275 } 276 277 @Ignore 278 @Test refresh_connectedWatch_checkSummary()279 public void refresh_connectedWatch_checkSummary() { 280 when(mBluetoothDevice.getMetadata( 281 BluetoothDevice.METADATA_DEVICE_TYPE)).thenReturn( 282 BluetoothDevice.DEVICE_TYPE_WATCH.getBytes()); 283 when(mCachedDevice.isConnected()).thenReturn(true); 284 when(mCachedDevice.getConnectionSummary(/* shortSummary= */ true)) 285 .thenReturn(DEVICE_SUMMARY); 286 287 mController.refresh(); 288 289 assertThat(((TextView) (mLayoutPreference.findViewById(R.id.entity_header_summary))) 290 .getText()).isEqualTo(DEVICE_SUMMARY); 291 } 292 293 @Test refresh_withLowBatteryAndUncharged_showAlertIcon()294 public void refresh_withLowBatteryAndUncharged_showAlertIcon() { 295 when(mBluetoothDevice.getMetadata( 296 BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn( 297 String.valueOf(true).getBytes()); 298 when(mBluetoothDevice.getMetadata( 299 BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY)).thenReturn( 300 String.valueOf(LOW_BATTERY_LEVEL).getBytes()); 301 when(mBluetoothDevice.getMetadata( 302 BluetoothDevice.METADATA_UNTETHERED_RIGHT_BATTERY)).thenReturn( 303 String.valueOf(LOW_BATTERY_LEVEL).getBytes()); 304 when(mBluetoothDevice.getMetadata( 305 BluetoothDevice.METADATA_UNTETHERED_CASE_BATTERY)).thenReturn( 306 String.valueOf(CASE_LOW_BATTERY_LEVEL).getBytes()); 307 when(mBluetoothDevice.getMetadata( 308 BluetoothDevice.METADATA_UNTETHERED_LEFT_CHARGING)).thenReturn( 309 String.valueOf(false).getBytes()); 310 when(mBluetoothDevice.getMetadata( 311 BluetoothDevice.METADATA_UNTETHERED_RIGHT_CHARGING)).thenReturn( 312 String.valueOf(true).getBytes()); 313 when(mBluetoothDevice.getMetadata( 314 BluetoothDevice.METADATA_UNTETHERED_CASE_CHARGING)).thenReturn( 315 String.valueOf(false).getBytes()); 316 when(mCachedDevice.isConnected()).thenReturn(true); 317 318 mController.refresh(); 319 320 assertBatteryIcon(mLayoutPreference.findViewById(R.id.layout_left), 321 R.drawable.ic_battery_alert_24dp); 322 assertBatteryIcon(mLayoutPreference.findViewById(R.id.layout_right), /* resId= */-1); 323 assertBatteryIcon(mLayoutPreference.findViewById(R.id.layout_middle), 324 R.drawable.ic_battery_alert_24dp); 325 } 326 327 @Test getAvailabilityStatus_untetheredHeadsetWithConfigOn_returnAvailable()328 public void getAvailabilityStatus_untetheredHeadsetWithConfigOn_returnAvailable() { 329 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_UI, 330 SettingsUIDeviceConfig.BT_ADVANCED_HEADER_ENABLED, "true", true); 331 when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)) 332 .thenReturn("true".getBytes()); 333 334 assertThat(mController.getAvailabilityStatus()).isEqualTo( 335 BasePreferenceController.AVAILABLE); 336 } 337 338 @Test getAvailabilityStatus_untetheredHeadsetWithConfigOff_returnUnavailable()339 public void getAvailabilityStatus_untetheredHeadsetWithConfigOff_returnUnavailable() { 340 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_UI, 341 SettingsUIDeviceConfig.BT_ADVANCED_HEADER_ENABLED, "false", true); 342 when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)) 343 .thenReturn("true".getBytes()); 344 345 assertThat(mController.getAvailabilityStatus()).isEqualTo( 346 BasePreferenceController.CONDITIONALLY_UNAVAILABLE); 347 } 348 349 @Test getAvailabilityStatus_notUntetheredHeadsetWithConfigOn_returnUnavailable()350 public void getAvailabilityStatus_notUntetheredHeadsetWithConfigOn_returnUnavailable() { 351 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_UI, 352 SettingsUIDeviceConfig.BT_ADVANCED_HEADER_ENABLED, "true", true); 353 when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)) 354 .thenReturn("false".getBytes()); 355 356 assertThat(mController.getAvailabilityStatus()).isEqualTo( 357 BasePreferenceController.CONDITIONALLY_UNAVAILABLE); 358 } 359 360 @Test getAvailabilityStatus_notUntetheredHeadsetWithConfigOff_returnUnavailable()361 public void getAvailabilityStatus_notUntetheredHeadsetWithConfigOff_returnUnavailable() { 362 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_UI, 363 SettingsUIDeviceConfig.BT_ADVANCED_HEADER_ENABLED, "false", true); 364 when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)) 365 .thenReturn("false".getBytes()); 366 367 assertThat(mController.getAvailabilityStatus()).isEqualTo( 368 BasePreferenceController.CONDITIONALLY_UNAVAILABLE); 369 } 370 371 @Test updateIcon_existInCache_setImageBitmap()372 public void updateIcon_existInCache_setImageBitmap() { 373 mController.mIconCache.put(ICON_URI, mBitmap); 374 375 mController.updateIcon(mImageView, ICON_URI); 376 377 verify(mImageView).setImageBitmap(mBitmap); 378 } 379 380 @Test onStart_isAvailable_registerCallback()381 public void onStart_isAvailable_registerCallback() { 382 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_UI, 383 SettingsUIDeviceConfig.BT_ADVANCED_HEADER_ENABLED, "true", true); 384 when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)) 385 .thenReturn("true".getBytes()); 386 Set<CachedBluetoothDevice> cacheBluetoothDevices = new HashSet<>(); 387 when(mCachedDevice.getMemberDevice()).thenReturn(cacheBluetoothDevices); 388 when(mBluetoothAdapter.addOnMetadataChangedListener( 389 mBluetoothDevice, mContext.getMainExecutor(), mController.mMetadataListener)) 390 .thenReturn(true); 391 392 mController.onStart(); 393 394 verify(mCachedDevice).registerCallback(mController); 395 verify(mBluetoothAdapter).addOnMetadataChangedListener(mBluetoothDevice, 396 mContext.getMainExecutor(), mController.mMetadataListener); 397 } 398 399 @Test onStart_notAvailable_notNeedToRegisterCallback()400 public void onStart_notAvailable_notNeedToRegisterCallback() { 401 when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)) 402 .thenReturn("false".getBytes()); 403 404 mController.onStart(); 405 406 verify(mCachedDevice, never()).registerCallback(mController); 407 verify(mBluetoothAdapter, never()).addOnMetadataChangedListener(mBluetoothDevice, 408 mContext.getMainExecutor(), mController.mMetadataListener); 409 } 410 411 @Test onStart_isAvailableButNoBluetoothDevice_notNeedToRegisterCallback()412 public void onStart_isAvailableButNoBluetoothDevice_notNeedToRegisterCallback() { 413 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_UI, 414 SettingsUIDeviceConfig.BT_ADVANCED_HEADER_ENABLED, "true", true); 415 when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)) 416 .thenReturn("true".getBytes()); 417 when(mCachedDevice.getDevice()).thenReturn(null); 418 Set<CachedBluetoothDevice> cacheBluetoothDevices = new HashSet<>(); 419 when(mCachedDevice.getMemberDevice()).thenReturn(cacheBluetoothDevices); 420 421 mController.onStart(); 422 423 verify(mCachedDevice, never()).registerCallback(mController); 424 verify(mBluetoothAdapter, never()).addOnMetadataChangedListener(mBluetoothDevice, 425 mContext.getMainExecutor(), mController.mMetadataListener); 426 } 427 428 @Test onStop_availableAndHasBluetoothDevice_unregisterCallback()429 public void onStop_availableAndHasBluetoothDevice_unregisterCallback() { 430 onStart_isAvailable_registerCallback(); 431 432 mController.onStop(); 433 434 verify(mCachedDevice).unregisterCallback(mController); 435 verify(mBluetoothAdapter).removeOnMetadataChangedListener(mBluetoothDevice, 436 mController.mMetadataListener); 437 } 438 439 @Test onStop_noBluetoothDevice_noNeedToUnregisterCallback()440 public void onStop_noBluetoothDevice_noNeedToUnregisterCallback() { 441 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_UI, 442 SettingsUIDeviceConfig.BT_ADVANCED_HEADER_ENABLED, "true", true); 443 when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)) 444 .thenReturn("true".getBytes()); 445 when(mCachedDevice.getDevice()).thenReturn(null); 446 447 mController.onStart(); 448 mController.onStop(); 449 450 verify(mCachedDevice, never()).unregisterCallback(mController); 451 verify(mBluetoothAdapter, never()).removeOnMetadataChangedListener(mBluetoothDevice, 452 mController.mMetadataListener); 453 } 454 455 @Test onDestroy_recycleBitmap()456 public void onDestroy_recycleBitmap() { 457 mController.mIconCache.put(ICON_URI, mBitmap); 458 459 mController.onDestroy(); 460 461 assertThat(mController.mIconCache).isEmpty(); 462 verify(mBitmap).recycle(); 463 } 464 465 @Test estimateReadyIsBothAvailable_showsView()466 public void estimateReadyIsBothAvailable_showsView() { 467 mController.mIsLeftDeviceEstimateReady = true; 468 mController.mIsRightDeviceEstimateReady = true; 469 470 mController.showBothDevicesBatteryPredictionIfNecessary(); 471 472 assertBatteryPredictionVisible(mLayoutPreference.findViewById(R.id.layout_left), 473 View.VISIBLE); 474 assertBatteryPredictionVisible(mLayoutPreference.findViewById(R.id.layout_right), 475 View.VISIBLE); 476 } 477 478 @Test leftDeviceEstimateIsReadyRightDeviceIsNotReady_notShowView()479 public void leftDeviceEstimateIsReadyRightDeviceIsNotReady_notShowView() { 480 mController.mIsLeftDeviceEstimateReady = true; 481 mController.mIsRightDeviceEstimateReady = false; 482 483 mController.showBothDevicesBatteryPredictionIfNecessary(); 484 485 assertBatteryPredictionVisible(mLayoutPreference.findViewById(R.id.layout_left), 486 View.GONE); 487 assertBatteryPredictionVisible(mLayoutPreference.findViewById(R.id.layout_right), 488 View.GONE); 489 } 490 491 @Test leftDeviceEstimateIsNotReadyRightDeviceIsReady_notShowView()492 public void leftDeviceEstimateIsNotReadyRightDeviceIsReady_notShowView() { 493 mController.mIsLeftDeviceEstimateReady = false; 494 mController.mIsRightDeviceEstimateReady = true; 495 496 mController.showBothDevicesBatteryPredictionIfNecessary(); 497 498 assertBatteryPredictionVisible(mLayoutPreference.findViewById(R.id.layout_left), 499 View.GONE); 500 assertBatteryPredictionVisible(mLayoutPreference.findViewById(R.id.layout_right), 501 View.GONE); 502 } 503 504 @Test bothDevicesEstimateIsNotReady_notShowView()505 public void bothDevicesEstimateIsNotReady_notShowView() { 506 mController.mIsLeftDeviceEstimateReady = false; 507 mController.mIsRightDeviceEstimateReady = false; 508 509 mController.showBothDevicesBatteryPredictionIfNecessary(); 510 511 assertBatteryPredictionVisible(mLayoutPreference.findViewById(R.id.layout_left), 512 View.GONE); 513 assertBatteryPredictionVisible(mLayoutPreference.findViewById(R.id.layout_right), 514 View.GONE); 515 } 516 517 @Test showBatteryPredictionIfNecessary_estimateReadyIsAvailable_showCorrectValue()518 public void showBatteryPredictionIfNecessary_estimateReadyIsAvailable_showCorrectValue() { 519 final String leftBatteryPrediction = 520 StringUtil.formatElapsedTime(mContext, 12000000, false, false).toString(); 521 final String rightBatteryPrediction = 522 StringUtil.formatElapsedTime(mContext, 1200000, false, false).toString(); 523 524 mController.showBatteryPredictionIfNecessary(1, 12000000, 525 mLayoutPreference.findViewById(R.id.layout_left)); 526 mController.showBatteryPredictionIfNecessary(1, 1200000, 527 mLayoutPreference.findViewById(R.id.layout_right)); 528 529 assertBatteryPrediction(mLayoutPreference.findViewById(R.id.layout_left), 530 leftBatteryPrediction); 531 assertBatteryPrediction(mLayoutPreference.findViewById(R.id.layout_right), 532 rightBatteryPrediction); 533 } 534 assertBatteryPredictionVisible(LinearLayout linearLayout, int visible)535 private void assertBatteryPredictionVisible(LinearLayout linearLayout, int visible) { 536 final TextView textView = linearLayout.findViewById(R.id.bt_battery_prediction); 537 assertThat(textView.getVisibility()).isEqualTo(visible); 538 } 539 assertBatteryPrediction(LinearLayout linearLayout, String prediction)540 private void assertBatteryPrediction(LinearLayout linearLayout, String prediction) { 541 final TextView textView = linearLayout.findViewById(R.id.bt_battery_prediction); 542 assertThat(textView.getText().toString()).isEqualTo(prediction); 543 } 544 assertBatteryLevel(LinearLayout linearLayout, int batteryLevel)545 private void assertBatteryLevel(LinearLayout linearLayout, int batteryLevel) { 546 final TextView textView = linearLayout.findViewById(R.id.bt_battery_summary); 547 assertThat(textView.getText().toString()).isEqualTo( 548 com.android.settings.Utils.formatPercentage(batteryLevel)); 549 } 550 assertBatteryIcon(LinearLayout linearLayout, int resId)551 private void assertBatteryIcon(LinearLayout linearLayout, int resId) { 552 final ImageView imageView = linearLayout.findViewById(R.id.bt_battery_icon); 553 assertThat(shadowOf(imageView.getDrawable()).getCreatedFromResId()) 554 .isEqualTo(resId); 555 } 556 557 } 558