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 17 package com.android.settings.fuelgauge; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static com.google.common.truth.Truth.assertWithMessage; 21 22 import static org.mockito.ArgumentMatchers.anyBoolean; 23 import static org.mockito.ArgumentMatchers.anyInt; 24 import static org.mockito.ArgumentMatchers.anyLong; 25 import static org.mockito.ArgumentMatchers.anyString; 26 import static org.mockito.ArgumentMatchers.eq; 27 import static org.mockito.Mockito.any; 28 import static org.mockito.Mockito.doAnswer; 29 import static org.mockito.Mockito.doReturn; 30 import static org.mockito.Mockito.mock; 31 import static org.mockito.Mockito.never; 32 import static org.mockito.Mockito.spy; 33 import static org.mockito.Mockito.times; 34 import static org.mockito.Mockito.verify; 35 import static org.mockito.Mockito.when; 36 37 import android.content.Context; 38 import android.content.Intent; 39 import android.os.BatteryManager; 40 import android.os.BatteryStats; 41 import android.os.BatteryUsageStats; 42 import android.os.SystemClock; 43 import android.os.SystemProperties; 44 import android.provider.Settings; 45 import android.util.SparseIntArray; 46 47 import com.android.internal.os.BatteryStatsHistoryIterator; 48 import com.android.settings.testutils.BatteryTestUtils; 49 import com.android.settings.testutils.FakeFeatureFactory; 50 import com.android.settings.widget.UsageView; 51 import com.android.settingslib.fuelgauge.Estimate; 52 import com.android.settingslib.utils.PowerUtil; 53 54 import org.junit.After; 55 import org.junit.Before; 56 import org.junit.Ignore; 57 import org.junit.Test; 58 import org.junit.runner.RunWith; 59 import org.mockito.ArgumentCaptor; 60 import org.mockito.Mock; 61 import org.mockito.MockitoAnnotations; 62 import org.robolectric.RobolectricTestRunner; 63 import org.robolectric.RuntimeEnvironment; 64 65 import java.time.Duration; 66 import java.time.Instant; 67 import java.util.Locale; 68 import java.util.Map; 69 import java.util.TimeZone; 70 import java.util.concurrent.TimeUnit; 71 72 @RunWith(RobolectricTestRunner.class) 73 public class BatteryInfoTest { 74 75 private static final String STATUS_CHARGING_NO_TIME = "50% - charging"; 76 private static final String STATUS_CHARGING_TIME = "50% - 0 min left until full"; 77 private static final String STATUS_NOT_CHARGING = "Not charging"; 78 private static final String STATUS_CHARGING_FUTURE_BYPASS = "50% - Charging"; 79 private static final String STATUS_CHARGING_PAUSED = 80 "50% - Charging on hold to protect battery"; 81 private static final long REMAINING_TIME_NULL = -1; 82 private static final long REMAINING_TIME = 2; 83 // Strings are defined in frameworks/base/packages/SettingsLib/res/values/strings.xml 84 private static final String ENHANCED_STRING_SUFFIX = "based on your usage"; 85 private static final String BATTERY_RUN_OUT_PREFIX = "Battery may run out by"; 86 private static final long TEST_CHARGE_TIME_REMAINING = TimeUnit.MINUTES.toMicros(1); 87 private static final String TEST_CHARGE_TIME_REMAINING_STRINGIFIED = "1 min left until full"; 88 private static final String TEST_BATTERY_LEVEL_10 = "10%"; 89 private static final String FIFTEEN_MIN_FORMATTED = "15 min"; 90 private static final Estimate MOCK_ESTIMATE = 91 new Estimate( 92 1000, /* estimateMillis */ 93 false, /* isBasedOnUsage */ 94 1000 /* averageDischargeTime */); 95 private static final Map<ChargingType, Integer> CHARGING_TYPE_MAP = 96 Map.of( 97 ChargingType.WIRED, BatteryManager.BATTERY_PLUGGED_AC, 98 ChargingType.WIRELESS, BatteryManager.BATTERY_PLUGGED_WIRELESS, 99 ChargingType.DOCKED, BatteryManager.BATTERY_PLUGGED_DOCK, 100 ChargingType.NONE, 0); 101 private static final Map<ChargingSpeed, Integer> CHARGING_SPEED_MAP = 102 Map.of( 103 ChargingSpeed.FAST, 1501000, 104 ChargingSpeed.REGULAR, 1500000, 105 ChargingSpeed.SLOW, 999999); 106 private static final long UNUSED_TIME_MS = -1L; 107 108 private Intent mDisChargingBatteryBroadcast; 109 private Intent mChargingBatteryBroadcast; 110 private Context mContext; 111 private FakeFeatureFactory mFeatureFactory; 112 private TimeZone mOriginalTimeZone; 113 114 @Mock private BatteryUsageStats mBatteryUsageStats; 115 116 @Before setUp()117 public void setUp() { 118 MockitoAnnotations.initMocks(this); 119 mContext = spy(RuntimeEnvironment.application); 120 mFeatureFactory = FakeFeatureFactory.setupForTest(); 121 122 mDisChargingBatteryBroadcast = BatteryTestUtils.getDischargingIntent(); 123 124 mChargingBatteryBroadcast = BatteryTestUtils.getChargingIntent(); 125 126 doReturn(false).when(mFeatureFactory.powerUsageFeatureProvider).isExtraDefend(); 127 Settings.Global.putInt( 128 mContext.getContentResolver(), 129 BatteryUtils.SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 130 0); 131 132 // Reset static cache for testing purpose. 133 com.android.settingslib.fuelgauge.BatteryUtils.setChargingStringV2Enabled(null); 134 135 mOriginalTimeZone = TimeZone.getDefault(); 136 } 137 138 @After tearDown()139 public void tearDown() throws Exception { 140 TimeZone.setDefault(mOriginalTimeZone); 141 } 142 143 @Test getBatteryInfo_hasStatusLabel()144 public void getBatteryInfo_hasStatusLabel() { 145 doReturn(REMAINING_TIME_NULL).when(mBatteryUsageStats).getBatteryTimeRemainingMs(); 146 BatteryInfo info = 147 BatteryInfo.getBatteryInfoOld( 148 mContext, 149 mDisChargingBatteryBroadcast, 150 mBatteryUsageStats, 151 SystemClock.elapsedRealtime() * 1000, 152 true /* shortString */); 153 154 assertThat(info.statusLabel).isEqualTo(STATUS_NOT_CHARGING); 155 } 156 157 @Test getBatteryInfo_doNotShowChargingMethod_hasRemainingTime()158 public void getBatteryInfo_doNotShowChargingMethod_hasRemainingTime() { 159 doReturn(REMAINING_TIME).when(mBatteryUsageStats).getChargeTimeRemainingMs(); 160 BatteryInfo info = 161 BatteryInfo.getBatteryInfoOld( 162 mContext, 163 mChargingBatteryBroadcast, 164 mBatteryUsageStats, 165 SystemClock.elapsedRealtime() * 1000, 166 false /* shortString */); 167 168 assertThat(info.chargeLabel.toString()).isEqualTo(STATUS_CHARGING_TIME); 169 } 170 171 @Test getBatteryInfo_doNotShowChargingMethod_noRemainingTime()172 public void getBatteryInfo_doNotShowChargingMethod_noRemainingTime() { 173 doReturn(REMAINING_TIME_NULL).when(mBatteryUsageStats).getChargeTimeRemainingMs(); 174 BatteryInfo info = 175 BatteryInfo.getBatteryInfoOld( 176 mContext, 177 mChargingBatteryBroadcast, 178 mBatteryUsageStats, 179 SystemClock.elapsedRealtime() * 1000, 180 false /* shortString */); 181 182 assertThat(info.chargeLabel.toString()).ignoringCase().isEqualTo(STATUS_CHARGING_NO_TIME); 183 } 184 185 @Test getBatteryInfo_pluggedInUsingShortString_usesCorrectData()186 public void getBatteryInfo_pluggedInUsingShortString_usesCorrectData() { 187 doReturn(TEST_CHARGE_TIME_REMAINING / 1000) 188 .when(mBatteryUsageStats) 189 .getChargeTimeRemainingMs(); 190 BatteryInfo info = 191 BatteryInfo.getBatteryInfoOld( 192 mContext, 193 mChargingBatteryBroadcast, 194 mBatteryUsageStats, 195 SystemClock.elapsedRealtime() * 1000, 196 true /* shortString */); 197 198 assertThat(info.discharging).isEqualTo(false); 199 assertThat(info.chargeLabel.toString()).isEqualTo("50% - 1 min left until full"); 200 } 201 202 @Test getBatteryInfo_basedOnUsageTrueMoreThanFifteenMinutes_usesCorrectString()203 public void getBatteryInfo_basedOnUsageTrueMoreThanFifteenMinutes_usesCorrectString() { 204 Estimate estimate = 205 new Estimate( 206 Duration.ofHours(4).toMillis(), 207 true /* isBasedOnUsage */, 208 1000 /* averageDischargeTime */); 209 BatteryInfo info = 210 BatteryInfo.getBatteryInfo( 211 mContext, 212 mDisChargingBatteryBroadcast, 213 mBatteryUsageStats, 214 estimate, 215 SystemClock.elapsedRealtime() * 1000, 216 false /* shortString */); 217 BatteryInfo info2 = 218 BatteryInfo.getBatteryInfo( 219 mContext, 220 mDisChargingBatteryBroadcast, 221 mBatteryUsageStats, 222 estimate, 223 SystemClock.elapsedRealtime() * 1000, 224 true /* shortString */); 225 226 // Both long and short strings should not have extra text 227 assertThat(info.remainingLabel.toString()).doesNotContain(ENHANCED_STRING_SUFFIX); 228 assertThat(info.suggestionLabel).contains(BATTERY_RUN_OUT_PREFIX); 229 assertThat(info2.remainingLabel.toString()).doesNotContain(ENHANCED_STRING_SUFFIX); 230 assertThat(info2.suggestionLabel).contains(BATTERY_RUN_OUT_PREFIX); 231 } 232 233 @Test 234 @Ignore getBatteryInfo_MoreThanOneDay_suggestionLabelIsCorrectString()235 public void getBatteryInfo_MoreThanOneDay_suggestionLabelIsCorrectString() { 236 Estimate estimate = 237 new Estimate( 238 Duration.ofDays(3).toMillis(), 239 true /* isBasedOnUsage */, 240 1000 /* averageDischargeTime */); 241 BatteryInfo info = 242 BatteryInfo.getBatteryInfo( 243 mContext, 244 mDisChargingBatteryBroadcast, 245 mBatteryUsageStats, 246 estimate, 247 SystemClock.elapsedRealtime() * 1000, 248 false /* shortString */); 249 250 assertThat(info.suggestionLabel).doesNotContain(BATTERY_RUN_OUT_PREFIX); 251 } 252 253 @Test getBatteryInfo_basedOnUsageFalse_usesDefaultString()254 public void getBatteryInfo_basedOnUsageFalse_usesDefaultString() { 255 BatteryInfo info = 256 BatteryInfo.getBatteryInfo( 257 mContext, 258 mDisChargingBatteryBroadcast, 259 mBatteryUsageStats, 260 MOCK_ESTIMATE, 261 SystemClock.elapsedRealtime() * 1000, 262 false /* shortString */); 263 BatteryInfo info2 = 264 BatteryInfo.getBatteryInfo( 265 mContext, 266 mDisChargingBatteryBroadcast, 267 mBatteryUsageStats, 268 MOCK_ESTIMATE, 269 SystemClock.elapsedRealtime() * 1000, 270 true /* shortString */); 271 272 assertThat(info.remainingLabel.toString()).doesNotContain(ENHANCED_STRING_SUFFIX); 273 assertThat(info2.remainingLabel.toString()).doesNotContain(ENHANCED_STRING_SUFFIX); 274 } 275 276 @Test getBatteryInfo_charging_usesChargeTime()277 public void getBatteryInfo_charging_usesChargeTime() { 278 doReturn(TEST_CHARGE_TIME_REMAINING / 1000) 279 .when(mBatteryUsageStats) 280 .getChargeTimeRemainingMs(); 281 282 BatteryInfo info = 283 BatteryInfo.getBatteryInfo( 284 mContext, 285 mChargingBatteryBroadcast, 286 mBatteryUsageStats, 287 MOCK_ESTIMATE, 288 SystemClock.elapsedRealtime() * 1000, 289 false /* shortString */); 290 291 assertThat(info.remainingTimeUs).isEqualTo(TEST_CHARGE_TIME_REMAINING); 292 assertThat(info.remainingLabel.toString()) 293 .isEqualTo(TEST_CHARGE_TIME_REMAINING_STRINGIFIED); 294 } 295 296 @Test getBatteryInfo_pluggedInWithFullBattery_onlyShowBatteryLevel()297 public void getBatteryInfo_pluggedInWithFullBattery_onlyShowBatteryLevel() { 298 mChargingBatteryBroadcast.putExtra(BatteryManager.EXTRA_LEVEL, 100); 299 300 BatteryInfo info = 301 BatteryInfo.getBatteryInfo( 302 mContext, 303 mChargingBatteryBroadcast, 304 mBatteryUsageStats, 305 MOCK_ESTIMATE, 306 SystemClock.elapsedRealtime() * 1000, 307 false /* shortString */); 308 309 assertThat(info.chargeLabel).isEqualTo("100%"); 310 } 311 312 @Test getBatteryInfo_chargingWithDefender_updateChargeLabel()313 public void getBatteryInfo_chargingWithDefender_updateChargeLabel() { 314 doReturn(TEST_CHARGE_TIME_REMAINING).when(mBatteryUsageStats).getChargeTimeRemainingMs(); 315 doReturn(true) 316 .when(mFeatureFactory.powerUsageFeatureProvider) 317 .isBatteryDefend(any(BatteryInfo.class)); 318 mChargingBatteryBroadcast.putExtra( 319 BatteryManager.EXTRA_CHARGING_STATUS, 320 BatteryManager.CHARGING_POLICY_ADAPTIVE_LONGLIFE); 321 322 BatteryInfo info = 323 BatteryInfo.getBatteryInfo( 324 mContext, 325 mChargingBatteryBroadcast, 326 mBatteryUsageStats, 327 MOCK_ESTIMATE, 328 SystemClock.elapsedRealtime() * 1000, 329 false /* shortString */); 330 331 assertThat(info.isBatteryDefender).isTrue(); 332 assertThat(info.chargeLabel.toString()).contains(STATUS_CHARGING_PAUSED); 333 } 334 335 @Test getBatteryInfo_getChargeTimeRemaining_updateSettingsGlobal()336 public void getBatteryInfo_getChargeTimeRemaining_updateSettingsGlobal() { 337 doReturn(TEST_CHARGE_TIME_REMAINING).when(mBatteryUsageStats).getChargeTimeRemainingMs(); 338 339 BatteryInfo.getBatteryInfo( 340 mContext, 341 mChargingBatteryBroadcast, 342 mBatteryUsageStats, 343 MOCK_ESTIMATE, 344 SystemClock.elapsedRealtime() * 1000, 345 false /* shortString */); 346 347 assertThat(BatteryInfo.getSettingsChargeTimeRemaining(mContext)) 348 .isEqualTo(TEST_CHARGE_TIME_REMAINING); 349 } 350 351 @Test getBatteryInfo_differentChargeTimeRemaining_updateSettingsGlobal()352 public void getBatteryInfo_differentChargeTimeRemaining_updateSettingsGlobal() { 353 doReturn(TEST_CHARGE_TIME_REMAINING).when(mBatteryUsageStats).getChargeTimeRemainingMs(); 354 final long newTimeToFull = 300L; 355 doReturn(newTimeToFull).when(mBatteryUsageStats).getChargeTimeRemainingMs(); 356 357 BatteryInfo.getBatteryInfo( 358 mContext, 359 mChargingBatteryBroadcast, 360 mBatteryUsageStats, 361 MOCK_ESTIMATE, 362 SystemClock.elapsedRealtime() * 1000, 363 false /* shortString */); 364 365 assertThat(BatteryInfo.getSettingsChargeTimeRemaining(mContext)).isEqualTo(newTimeToFull); 366 } 367 368 @Test getBatteryInfo_dockDefenderActive_updateChargeString()369 public void getBatteryInfo_dockDefenderActive_updateChargeString() { 370 doReturn(TEST_CHARGE_TIME_REMAINING / 1000) 371 .when(mBatteryUsageStats) 372 .getChargeTimeRemainingMs(); 373 doReturn(true).when(mFeatureFactory.powerUsageFeatureProvider).isExtraDefend(); 374 doReturn(true) 375 .when(mFeatureFactory.powerUsageFeatureProvider) 376 .isBatteryDefend(any(BatteryInfo.class)); 377 Intent intent = 378 createBatteryIntent( 379 BatteryManager.BATTERY_PLUGGED_DOCK, 380 /* level= */ 50, 381 BatteryManager.BATTERY_STATUS_CHARGING) 382 .putExtra( 383 BatteryManager.EXTRA_CHARGING_STATUS, 384 BatteryManager.CHARGING_POLICY_ADAPTIVE_LONGLIFE); 385 386 BatteryInfo info = 387 BatteryInfo.getBatteryInfo( 388 mContext, 389 intent, 390 mBatteryUsageStats, 391 MOCK_ESTIMATE, 392 SystemClock.elapsedRealtime() * 1000, 393 false /* shortString */); 394 395 assertThat(info.chargeLabel.toString()).contains(STATUS_CHARGING_PAUSED); 396 } 397 398 @Test getBatteryInfo_dockDefenderTemporarilyBypassed_updateChargeLabel()399 public void getBatteryInfo_dockDefenderTemporarilyBypassed_updateChargeLabel() { 400 doReturn(REMAINING_TIME).when(mBatteryUsageStats).getChargeTimeRemainingMs(); 401 mChargingBatteryBroadcast.putExtra( 402 BatteryManager.EXTRA_CHARGING_STATUS, BatteryManager.CHARGING_POLICY_DEFAULT); 403 Settings.Global.putInt( 404 mContext.getContentResolver(), 405 BatteryUtils.SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 406 1); 407 408 BatteryInfo info = 409 BatteryInfo.getBatteryInfo( 410 mContext, 411 createBatteryIntent( 412 BatteryManager.BATTERY_PLUGGED_DOCK, 413 /* level= */ 50, 414 BatteryManager.BATTERY_STATUS_CHARGING), 415 mBatteryUsageStats, 416 MOCK_ESTIMATE, 417 SystemClock.elapsedRealtime() * 1000, 418 false /* shortString */); 419 420 assertThat(info.chargeLabel.toString()).contains(STATUS_CHARGING_TIME); 421 } 422 423 @Test getBatteryInfo_dockDefenderFutureBypass_updateChargeLabel()424 public void getBatteryInfo_dockDefenderFutureBypass_updateChargeLabel() { 425 doReturn(false).when(mFeatureFactory.powerUsageFeatureProvider).isExtraDefend(); 426 mChargingBatteryBroadcast.putExtra( 427 BatteryManager.EXTRA_CHARGING_STATUS, BatteryManager.CHARGING_POLICY_DEFAULT); 428 429 BatteryInfo info = 430 BatteryInfo.getBatteryInfo( 431 mContext, 432 createBatteryIntent( 433 BatteryManager.BATTERY_PLUGGED_DOCK, 434 /* level= */ 50, 435 BatteryManager.BATTERY_STATUS_CHARGING), 436 mBatteryUsageStats, 437 MOCK_ESTIMATE, 438 SystemClock.elapsedRealtime() * 1000, 439 false /* shortString */); 440 441 assertThat(info.chargeLabel.toString()).contains(STATUS_CHARGING_FUTURE_BYPASS); 442 } 443 444 @Test getBatteryInfo_fastCharging_updateRemainingLabelAndStatusLabel()445 public void getBatteryInfo_fastCharging_updateRemainingLabelAndStatusLabel() { 446 prepareTestGetBatteryInfoEnvironment( 447 /* remainingTimeMs= */ Duration.ofMinutes(90).toMillis(), 448 /* chargingStringV2Enabled= */ false); 449 Intent batteryIntent = 450 createIntentForGetBatteryInfoTest( 451 ChargingType.WIRED, ChargingSpeed.FAST, /* batteryLevel= */ 61); 452 var expectedStatusLabel = "Charging rapidly"; 453 var expectedRemainingLabel = "1 hr, 30 min left until full"; 454 var expectedChargeLabel = "61% - " + expectedRemainingLabel; 455 456 assertGetBatteryInfo( 457 batteryIntent, 458 /* currentTimeMillis= */ UNUSED_TIME_MS, 459 expectedStatusLabel, 460 expectedRemainingLabel, 461 expectedChargeLabel); 462 } 463 464 @Test getBatteryInfo_regularCharging_updateRemainingLabelAndStatusLabel()465 public void getBatteryInfo_regularCharging_updateRemainingLabelAndStatusLabel() { 466 prepareTestGetBatteryInfoEnvironment( 467 /* remainingTimeMs= */ Duration.ofMinutes(80).toMillis(), 468 /* chargingStringV2Enabled= */ false); 469 Intent batteryIntent = 470 createIntentForGetBatteryInfoTest( 471 ChargingType.WIRED, ChargingSpeed.REGULAR, /* batteryLevel= */ 33); 472 var expectedStatusLabel = "Charging"; 473 var expectedRemainingLabel = "1 hr, 20 min left until full"; 474 var expectedChargeLabel = "33% - " + expectedRemainingLabel; 475 476 assertGetBatteryInfo( 477 batteryIntent, 478 /* currentTimeMillis= */ UNUSED_TIME_MS, 479 expectedStatusLabel, 480 expectedRemainingLabel, 481 expectedChargeLabel); 482 } 483 484 @Test getBatteryInfo_slowCharging_updateRemainingLabelAndStatusLabel()485 public void getBatteryInfo_slowCharging_updateRemainingLabelAndStatusLabel() { 486 prepareTestGetBatteryInfoEnvironment( 487 /* remainingTimeMs= */ Duration.ofMinutes(100).toMillis(), 488 /* chargingStringV2Enabled= */ false); 489 Intent batteryIntent = 490 createIntentForGetBatteryInfoTest( 491 ChargingType.WIRED, ChargingSpeed.SLOW, /* batteryLevel= */ 53); 492 var expectedStatusLabel = "Charging slowly"; 493 var expectedRemainingLabel = "1 hr, 40 min left until full"; 494 var expectedChargeLabel = "53% - " + expectedRemainingLabel; 495 496 assertGetBatteryInfo( 497 batteryIntent, 498 /* currentTimeMillis= */ UNUSED_TIME_MS, 499 expectedStatusLabel, 500 expectedRemainingLabel, 501 expectedChargeLabel); 502 } 503 504 @Test getBatteryInfo_wirelessCharging_updateRemainingLabelAndStatusLabel()505 public void getBatteryInfo_wirelessCharging_updateRemainingLabelAndStatusLabel() { 506 prepareTestGetBatteryInfoEnvironment( 507 /* remainingTimeMs= */ Duration.ofMinutes(130).toMillis(), 508 /* chargingStringV2Enabled= */ false); 509 Intent batteryIntent = 510 createIntentForGetBatteryInfoTest( 511 ChargingType.WIRELESS, ChargingSpeed.REGULAR, /* batteryLevel= */ 10); 512 var expectedStatusLabel = "Charging wirelessly"; 513 var expectedRemainingLabel = "2 hr, 10 min left until full"; 514 var expectedChargeLabel = "10% - " + expectedRemainingLabel; 515 516 assertGetBatteryInfo( 517 batteryIntent, 518 /* currentTimeMillis= */ UNUSED_TIME_MS, 519 expectedStatusLabel, 520 expectedRemainingLabel, 521 expectedChargeLabel); 522 } 523 524 @Test getBatteryInfo_dockedCharging_updateRemainingLabelAndStatusLabel()525 public void getBatteryInfo_dockedCharging_updateRemainingLabelAndStatusLabel() { 526 prepareTestGetBatteryInfoEnvironment( 527 /* remainingTimeMs= */ Duration.ofMinutes(30).toMillis(), 528 /* chargingStringV2Enabled= */ false); 529 Intent batteryIntent = 530 createIntentForGetBatteryInfoTest( 531 ChargingType.DOCKED, ChargingSpeed.REGULAR, /* batteryLevel= */ 51); 532 var expectedStatusLabel = "Charging"; 533 var expectedRemainingLabel = "30 min left until full"; 534 var expectedChargeLabel = "51% - " + expectedRemainingLabel; 535 536 assertGetBatteryInfo( 537 batteryIntent, 538 /* currentTimeMillis= */ UNUSED_TIME_MS, 539 expectedStatusLabel, 540 expectedRemainingLabel, 541 expectedChargeLabel); 542 } 543 544 @Test 545 @Ignore getBatteryInfo_fastChargingV2_updateRemainingLabelAndStatusLabel()546 public void getBatteryInfo_fastChargingV2_updateRemainingLabelAndStatusLabel() { 547 prepareTestGetBatteryInfoEnvironment( 548 /* remainingTimeMs= */ Duration.ofMinutes(30).toMillis(), 549 /* chargingStringV2Enabled= */ true); 550 Intent batteryIntent = 551 createIntentForGetBatteryInfoTest( 552 ChargingType.WIRED, ChargingSpeed.FAST, /* batteryLevel= */ 56); 553 var expectedStatusLabel = "Fast charging"; 554 var expectedRemainingLabel = "Full by "; 555 var expectedChargeLabel = "56% - " + expectedStatusLabel + " - " + expectedRemainingLabel; 556 var currentTimeMillis = Instant.parse("2024-04-01T13:00:00Z").toEpochMilli(); 557 558 assertGetBatteryInfo( 559 batteryIntent, 560 currentTimeMillis, 561 expectedStatusLabel, 562 expectedRemainingLabel, 563 expectedChargeLabel); 564 } 565 566 @Test getBatteryInfo_regularChargingV2_updateRemainingLabelAndStatusLabel()567 public void getBatteryInfo_regularChargingV2_updateRemainingLabelAndStatusLabel() { 568 prepareTestGetBatteryInfoEnvironment( 569 /* remainingTimeMs= */ Duration.ofHours(1).toMillis(), 570 /* chargingStringV2Enabled= */ true); 571 Intent batteryIntent = 572 createIntentForGetBatteryInfoTest( 573 ChargingType.WIRED, ChargingSpeed.REGULAR, /* batteryLevel= */ 12); 574 var expectedStatusLabel = "Charging"; 575 var expectedRemainingLabel = "Fully charged by "; 576 var expectedChargeLabel = "12% - " + expectedRemainingLabel; 577 var currentTimeMillis = Instant.parse("2024-04-01T13:00:00Z").toEpochMilli(); 578 579 assertGetBatteryInfo( 580 batteryIntent, 581 currentTimeMillis, 582 expectedStatusLabel, 583 expectedRemainingLabel, 584 expectedChargeLabel); 585 } 586 587 @Test getBatteryInfo_slowChargingV2_updateRemainingLabelAndStatusLabel()588 public void getBatteryInfo_slowChargingV2_updateRemainingLabelAndStatusLabel() { 589 prepareTestGetBatteryInfoEnvironment( 590 /* remainingTimeMs= */ Duration.ofHours(2).toMillis(), 591 /* chargingStringV2Enabled= */ true); 592 Intent batteryIntent = 593 createIntentForGetBatteryInfoTest( 594 ChargingType.WIRED, ChargingSpeed.SLOW, /* batteryLevel= */ 18); 595 var expectedStatusLabel = "Charging"; 596 var expectedRemainingLabel = "Fully charged by"; 597 var expectedChargeLabel = "18% - " + expectedRemainingLabel; 598 var currentTimeMillis = Instant.parse("2024-04-01T13:00:00Z").toEpochMilli(); 599 600 assertGetBatteryInfo( 601 batteryIntent, 602 currentTimeMillis, 603 expectedStatusLabel, 604 expectedRemainingLabel, 605 expectedChargeLabel); 606 } 607 608 @Test getBatteryInfo_wirelessChargingV2_updateRemainingLabelAndStatusLabel()609 public void getBatteryInfo_wirelessChargingV2_updateRemainingLabelAndStatusLabel() { 610 prepareTestGetBatteryInfoEnvironment( 611 /* remainingTimeMs= */ Duration.ofHours(1).toMillis(), 612 /* chargingStringV2Enabled= */ true); 613 Intent batteryIntent = 614 createIntentForGetBatteryInfoTest( 615 ChargingType.WIRELESS, ChargingSpeed.REGULAR, /* batteryLevel= */ 45); 616 var expectedStatusLabel = "Charging"; 617 var expectedRemainingLabel = "Fully charged by"; 618 var expectedChargeLabel = "45% - " + expectedRemainingLabel; 619 var currentTimeMillis = Instant.parse("2024-04-01T15:00:00Z").toEpochMilli(); 620 621 assertGetBatteryInfo( 622 batteryIntent, 623 currentTimeMillis, 624 expectedStatusLabel, 625 expectedRemainingLabel, 626 expectedChargeLabel); 627 } 628 629 @Test getBatteryInfo_dockedChargingV2_updateRemainingLabelAndStatusLabel()630 public void getBatteryInfo_dockedChargingV2_updateRemainingLabelAndStatusLabel() { 631 prepareTestGetBatteryInfoEnvironment( 632 /* remainingTimeMs= */ Duration.ofHours(1).toMillis(), 633 /* chargingStringV2Enabled= */ true); 634 Intent batteryIntent = 635 createIntentForGetBatteryInfoTest( 636 ChargingType.DOCKED, ChargingSpeed.REGULAR, /* batteryLevel= */ 66); 637 var expectedStatusLabel = "Charging"; 638 var expectedRemainingLabel = "Fully charged by"; 639 var expectedChargeLabel = "66% - " + expectedRemainingLabel; 640 var currentTimeMillis = Instant.parse("2021-02-09T13:00:00.00Z").toEpochMilli(); 641 642 assertGetBatteryInfo( 643 batteryIntent, 644 currentTimeMillis, 645 expectedStatusLabel, 646 expectedRemainingLabel, 647 expectedChargeLabel); 648 } 649 650 @Test getBatteryInfo_customizedWLCLabel_updateRemainingLabelAndStatusLabel()651 public void getBatteryInfo_customizedWLCLabel_updateRemainingLabelAndStatusLabel() { 652 prepareTestGetBatteryInfoEnvironment( 653 /* remainingTimeMs= */ Duration.ofHours(1).toMillis(), 654 /* chargingStringV2Enabled= */ true); 655 Intent batteryIntent = 656 createIntentForGetBatteryInfoTest( 657 ChargingType.WIRELESS, ChargingSpeed.REGULAR, /* batteryLevel= */ 45); 658 var expectedLabel = "Full by 8:00 AM"; 659 when(mFeatureFactory.batterySettingsFeatureProvider.getWirelessChargingRemainingLabel( 660 eq(mContext), anyLong(), anyLong())) 661 .thenReturn(expectedLabel); 662 var currentTimeMillis = Instant.parse("2021-02-09T13:00:00.00Z").toEpochMilli(); 663 var info = 664 BatteryInfo.getBatteryInfo( 665 mContext, 666 batteryIntent, 667 mBatteryUsageStats, 668 MOCK_ESTIMATE, 669 /* elapsedRealtimeUs= */ UNUSED_TIME_MS, 670 /* shortString= */ false, 671 /* currentTimeMillis= */ currentTimeMillis); 672 673 assertThat(info.remainingLabel).isEqualTo(expectedLabel); 674 } 675 676 @Test getBatteryInfo_noCustomizedWLCLabel_updateRemainingLabelAndStatusLabel()677 public void getBatteryInfo_noCustomizedWLCLabel_updateRemainingLabelAndStatusLabel() { 678 prepareTestGetBatteryInfoEnvironment( 679 /* remainingTimeMs= */ Duration.ofHours(1).toMillis(), 680 /* chargingStringV2Enabled= */ true); 681 Intent batteryIntent = 682 createIntentForGetBatteryInfoTest( 683 ChargingType.WIRELESS, ChargingSpeed.REGULAR, /* batteryLevel= */ 45); 684 when(mFeatureFactory.batterySettingsFeatureProvider.getWirelessChargingRemainingLabel( 685 eq(mContext), anyLong(), anyLong())) 686 .thenReturn(null); 687 var expectedStatusLabel = "Charging"; 688 var expectedRemainingLabel = "Fully charged by"; 689 var expectedChargeLabel = "45% - " + expectedRemainingLabel; 690 var currentTimeMillis = Instant.parse("2024-04-01T15:00:00Z").toEpochMilli(); 691 692 assertGetBatteryInfo( 693 batteryIntent, 694 currentTimeMillis, 695 expectedStatusLabel, 696 expectedRemainingLabel, 697 expectedChargeLabel); 698 } 699 700 @Test getBatteryInfo_noCustomWirelessChargingLabelWithV1_updateRemainingAndStatusLabel()701 public void getBatteryInfo_noCustomWirelessChargingLabelWithV1_updateRemainingAndStatusLabel() { 702 prepareTestGetBatteryInfoEnvironment( 703 /* remainingTimeMs= */ Duration.ofMinutes(130).toMillis(), 704 /* chargingStringV2Enabled= */ false); 705 Intent batteryIntent = 706 createIntentForGetBatteryInfoTest( 707 ChargingType.WIRELESS, ChargingSpeed.REGULAR, /* batteryLevel= */ 10); 708 when(mFeatureFactory.batterySettingsFeatureProvider.getWirelessChargingRemainingLabel( 709 eq(mContext), anyLong(), anyLong())) 710 .thenReturn(null); 711 var expectedStatusLabel = "Charging wirelessly"; 712 var expectedRemainingLabel = "2 hr, 10 min left until full"; 713 var expectedChargeLabel = "10% - " + expectedRemainingLabel; 714 715 assertGetBatteryInfo( 716 batteryIntent, 717 /* currentTimeMillis= */ UNUSED_TIME_MS, 718 expectedStatusLabel, 719 expectedRemainingLabel, 720 expectedChargeLabel); 721 } 722 723 @Test getBatteryInfo_chargeOptimizationMode_updateRemainingAndStatusLabel()724 public void getBatteryInfo_chargeOptimizationMode_updateRemainingAndStatusLabel() { 725 prepareTestGetBatteryInfoEnvironment( 726 /* remainingTimeMs= */ Duration.ofMinutes(130).toMillis(), 727 /* chargingStringV2Enabled= */ false); 728 Intent batteryIntent = 729 createIntentForGetBatteryInfoTest( 730 ChargingType.WIRED, ChargingSpeed.REGULAR, /* batteryLevel= */ 65); 731 var expectedRemainingLabel = "Expected remaining label"; 732 var expectedChargeLabel = "65% - " + expectedRemainingLabel; 733 when(mFeatureFactory.batterySettingsFeatureProvider.isChargingOptimizationMode( 734 eq(mContext), anyBoolean())) 735 .thenReturn(true); 736 when(mFeatureFactory.batterySettingsFeatureProvider.getChargingOptimizationRemainingLabel( 737 eq(mContext), anyInt(), anyInt(), anyLong(), anyLong())) 738 .thenReturn(expectedRemainingLabel); 739 when(mFeatureFactory.batterySettingsFeatureProvider.getChargingOptimizationChargeLabel( 740 eq(mContext), anyInt(), anyString(), anyLong(), anyLong())) 741 .thenReturn(expectedChargeLabel); 742 var expectedStatusLabel = "Charging"; 743 744 assertGetBatteryInfo( 745 batteryIntent, 746 /* currentTimeMillis= */ UNUSED_TIME_MS, 747 expectedStatusLabel, 748 expectedRemainingLabel, 749 expectedChargeLabel); 750 } 751 752 @Test getBatteryInfo_notChargeOptimizationModeWithV1_updateRemainingAndStatusLabel()753 public void getBatteryInfo_notChargeOptimizationModeWithV1_updateRemainingAndStatusLabel() { 754 prepareTestGetBatteryInfoEnvironment( 755 /* remainingTimeMs= */ Duration.ofMinutes(130).toMillis(), 756 /* chargingStringV2Enabled= */ false); 757 Intent batteryIntent = 758 createIntentForGetBatteryInfoTest( 759 ChargingType.WIRED, ChargingSpeed.REGULAR, /* batteryLevel= */ 65); 760 when(mFeatureFactory.batterySettingsFeatureProvider.isChargingOptimizationMode( 761 eq(mContext), anyBoolean())) 762 .thenReturn(false); 763 var expectedStatusLabel = "Charging"; 764 var expectedRemainingLabel = "2 hr, 10 min left until full"; 765 var expectedChargeLabel = "65% - " + expectedRemainingLabel; 766 767 assertGetBatteryInfo( 768 batteryIntent, 769 /* currentTimeMillis= */ UNUSED_TIME_MS, 770 expectedStatusLabel, 771 expectedRemainingLabel, 772 expectedChargeLabel); 773 } 774 775 @Test getBatteryInfo_notChargeOptimizationModeWithV2_updateRemainingAndStatusLabel()776 public void getBatteryInfo_notChargeOptimizationModeWithV2_updateRemainingAndStatusLabel() { 777 prepareTestGetBatteryInfoEnvironment( 778 /* remainingTimeMs= */ Duration.ofMinutes(130).toMillis(), 779 /* chargingStringV2Enabled= */ true); 780 Intent batteryIntent = 781 createIntentForGetBatteryInfoTest( 782 ChargingType.WIRED, ChargingSpeed.REGULAR, /* batteryLevel= */ 65); 783 when(mFeatureFactory.batterySettingsFeatureProvider.isChargingOptimizationMode( 784 eq(mContext), anyBoolean())) 785 .thenReturn(false); 786 var expectedStatusLabel = "Charging"; 787 var expectedRemainingLabel = "Fully charged by"; 788 var expectedChargeLabel = "65% - " + expectedRemainingLabel; 789 var currentTimeMillis = Instant.parse("2024-04-01T15:00:00Z").toEpochMilli(); 790 791 assertGetBatteryInfo( 792 batteryIntent, 793 currentTimeMillis, 794 expectedStatusLabel, 795 expectedRemainingLabel, 796 expectedChargeLabel); 797 } 798 799 @Test getBatteryInfo_longlife_shouldSetLonglife()800 public void getBatteryInfo_longlife_shouldSetLonglife() { 801 var batteryIntent = createIntentForLongLifeTest(/* hasLongLife= */ true); 802 803 var batteryInfo = 804 BatteryInfo.getBatteryInfo( 805 mContext, 806 batteryIntent, 807 mBatteryUsageStats, 808 /* estimate= */ MOCK_ESTIMATE, 809 /* elapsedRealtimeUs= */ 0L, 810 /* shortString= */ false, 811 /* currentTimeMs= */ 0L); 812 813 assertThat(batteryInfo.isLongLife).isTrue(); 814 } 815 816 @Test getBatteryInfo_noLonglife_shouldNotLonglife()817 public void getBatteryInfo_noLonglife_shouldNotLonglife() { 818 var batteryIntent = createIntentForLongLifeTest(/* hasLongLife= */ false); 819 820 var batteryInfo = 821 BatteryInfo.getBatteryInfo( 822 mContext, 823 batteryIntent, 824 mBatteryUsageStats, 825 /* estimate= */ MOCK_ESTIMATE, 826 /* elapsedRealtimeUs= */ 0L, 827 /* shortString= */ false, 828 /* currentTimeMs= */ 0L); 829 830 assertThat(batteryInfo.isLongLife).isFalse(); 831 } 832 833 @Test getBatteryInfo_plugTypeNoneIsChargeOptimization_chargingString()834 public void getBatteryInfo_plugTypeNoneIsChargeOptimization_chargingString() { 835 prepareTestGetBatteryInfoEnvironment( 836 /* remainingTimeMs= */ Duration.ofMinutes(130).toMillis(), 837 /* chargingStringV2Enabled= */ false); 838 Intent batteryIntent = 839 createIntentForGetBatteryInfoTest( 840 ChargingType.NONE, 841 ChargingSpeed.REGULAR, 842 /* batteryLevel= */ 85, 843 BatteryManager.BATTERY_STATUS_DISCHARGING, 844 /* isLonglife= */ true); 845 var expectedRemainingLabel = "Expected remaining label"; 846 var expectedChargeLabel = "85% - " + expectedRemainingLabel; 847 when(mFeatureFactory.batterySettingsFeatureProvider.isChargingOptimizationMode( 848 eq(mContext), anyBoolean())) 849 .thenReturn(true); 850 when(mFeatureFactory.batterySettingsFeatureProvider.getChargingOptimizationRemainingLabel( 851 eq(mContext), anyInt(), anyInt(), anyLong(), anyLong())) 852 .thenReturn(expectedRemainingLabel); 853 when(mFeatureFactory.batterySettingsFeatureProvider.getChargingOptimizationChargeLabel( 854 eq(mContext), anyInt(), anyString(), anyLong(), anyLong())) 855 .thenReturn(expectedChargeLabel); 856 var expectedStatusLabel = "Not charging"; 857 858 assertGetBatteryInfo( 859 batteryIntent, 860 /* currentTimeMillis= */ UNUSED_TIME_MS, 861 expectedStatusLabel, 862 expectedRemainingLabel, 863 expectedChargeLabel); 864 } 865 866 @Test getBatteryInfo_plugTypeNoneNotChargeOptimization_dischargingString()867 public void getBatteryInfo_plugTypeNoneNotChargeOptimization_dischargingString() { 868 prepareTestGetBatteryInfoEnvironment( 869 /* remainingTimeMs= */ Duration.ofMinutes(130).toMillis(), 870 /* chargingStringV2Enabled= */ false); 871 Intent batteryIntent = 872 createIntentForGetBatteryInfoTest( 873 ChargingType.NONE, 874 ChargingSpeed.REGULAR, 875 /* batteryLevel= */ 85, 876 BatteryManager.BATTERY_STATUS_DISCHARGING, 877 /* isLonglife= */ false); 878 var expectedRemainingLabel = 879 PowerUtil.getBatteryRemainingShortStringFormatted( 880 mContext, PowerUtil.convertUsToMs(1000L)); 881 when(mFeatureFactory.batterySettingsFeatureProvider.isChargingOptimizationMode( 882 eq(mContext), anyBoolean())) 883 .thenReturn(false); 884 var expectedStatusLabel = "Not charging"; 885 886 assertGetBatteryInfo( 887 batteryIntent, 888 /* currentTimeMillis= */ UNUSED_TIME_MS, 889 expectedStatusLabel, 890 expectedRemainingLabel, 891 expectedRemainingLabel); 892 } 893 894 private enum ChargingSpeed { 895 FAST, 896 REGULAR, 897 SLOW 898 } 899 900 private enum ChargingType { 901 WIRED, 902 WIRELESS, 903 DOCKED, 904 NONE 905 } 906 createIntentForLongLifeTest(Boolean hasLongLife)907 private static Intent createIntentForLongLifeTest(Boolean hasLongLife) { 908 return new Intent(Intent.ACTION_BATTERY_CHANGED) 909 .putExtra( 910 BatteryManager.EXTRA_CHARGING_STATUS, 911 hasLongLife 912 ? BatteryManager.CHARGING_POLICY_ADAPTIVE_LONGLIFE 913 : BatteryManager.CHARGING_POLICY_DEFAULT); 914 } 915 createIntentForGetBatteryInfoTest( ChargingType chargingType, ChargingSpeed chargingSpeed, int batteryLevel)916 private static Intent createIntentForGetBatteryInfoTest( 917 ChargingType chargingType, ChargingSpeed chargingSpeed, int batteryLevel) { 918 return createIntentForGetBatteryInfoTest( 919 chargingType, 920 chargingSpeed, 921 batteryLevel, 922 BatteryManager.BATTERY_STATUS_CHARGING, 923 /* isLonglife= */ false); 924 } 925 createIntentForGetBatteryInfoTest( ChargingType chargingType, ChargingSpeed chargingSpeed, int batteryLevel, int chargingStatus, boolean isLonglife)926 private static Intent createIntentForGetBatteryInfoTest( 927 ChargingType chargingType, 928 ChargingSpeed chargingSpeed, 929 int batteryLevel, 930 int chargingStatus, 931 boolean isLonglife) { 932 return createBatteryIntent( 933 CHARGING_TYPE_MAP.get(chargingType), batteryLevel, chargingStatus) 934 .putExtra( 935 BatteryManager.EXTRA_MAX_CHARGING_CURRENT, 936 CHARGING_SPEED_MAP.get(chargingSpeed)) 937 .putExtra(BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE, 5000000) 938 .putExtra( 939 BatteryManager.EXTRA_CHARGING_STATUS, 940 isLonglife 941 ? BatteryManager.CHARGING_POLICY_ADAPTIVE_LONGLIFE 942 : BatteryManager.CHARGING_POLICY_DEFAULT); 943 } 944 prepareTestGetBatteryInfoEnvironment( long remainingTimeMs, boolean chargingStringV2Enabled)945 private void prepareTestGetBatteryInfoEnvironment( 946 long remainingTimeMs, boolean chargingStringV2Enabled) { 947 when(mBatteryUsageStats.getChargeTimeRemainingMs()).thenReturn(remainingTimeMs); 948 SystemProperties.set( 949 com.android.settingslib.fuelgauge.BatteryUtils.PROPERTY_CHARGING_STRING_V2_KEY, 950 String.valueOf(chargingStringV2Enabled)); 951 Settings.Global.putInt( 952 mContext.getContentResolver(), 953 BatteryUtils.SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 954 1); 955 } 956 assertGetBatteryInfo( Intent batteryIntent, long currentTimeMillis, String expectedStatusLabel, String expectedRemainingLabel, String expectedChargeLabel)957 private void assertGetBatteryInfo( 958 Intent batteryIntent, 959 long currentTimeMillis, 960 String expectedStatusLabel, 961 String expectedRemainingLabel, 962 String expectedChargeLabel) { 963 mContext.getResources().getConfiguration().setLocale(Locale.US); 964 TimeZone.setDefault(TimeZone.getTimeZone("UTC")); 965 var info = 966 BatteryInfo.getBatteryInfo( 967 mContext, 968 batteryIntent, 969 mBatteryUsageStats, 970 MOCK_ESTIMATE, 971 /* elapsedRealtimeUs= */ UNUSED_TIME_MS, 972 /* shortString= */ false, 973 /* currentTimeMillis= */ currentTimeMillis); 974 975 assertWithMessage("statusLabel is incorrect") 976 .that(info.statusLabel) 977 .isEqualTo(expectedStatusLabel); 978 assertWithMessage("remainingLabel is incorrect") 979 .that(info.remainingLabel.toString()) 980 .contains(expectedRemainingLabel); 981 assertWithMessage("chargeLabel is incorrect") 982 .that(info.chargeLabel.toString()) 983 .contains(expectedChargeLabel); 984 } 985 createBatteryIntent(int plugged, int level, int status)986 private static Intent createBatteryIntent(int plugged, int level, int status) { 987 return new Intent() 988 .putExtra(BatteryManager.EXTRA_PLUGGED, plugged) 989 .putExtra(BatteryManager.EXTRA_LEVEL, level) 990 .putExtra(BatteryManager.EXTRA_SCALE, 100) 991 .putExtra(BatteryManager.EXTRA_STATUS, status); 992 } 993 994 // Make our battery stats return a sequence of battery events. mockBatteryStatsHistory()995 private void mockBatteryStatsHistory() { 996 // Mock out new data every time iterateBatteryStatsHistory is called. 997 doAnswer( 998 invocation -> { 999 BatteryStatsHistoryIterator iterator = 1000 mock(BatteryStatsHistoryIterator.class); 1001 when(iterator.next()) 1002 .thenReturn( 1003 makeHistoryIterm(1000, 99), 1004 makeHistoryIterm(1500, 98), 1005 makeHistoryIterm(2000, 97), 1006 null); 1007 return iterator; 1008 }) 1009 .when(mBatteryUsageStats) 1010 .iterateBatteryStatsHistory(); 1011 } 1012 makeHistoryIterm(long time, int batteryLevel)1013 private BatteryStats.HistoryItem makeHistoryIterm(long time, int batteryLevel) { 1014 BatteryStats.HistoryItem record = new BatteryStats.HistoryItem(); 1015 record.cmd = BatteryStats.HistoryItem.CMD_UPDATE; 1016 record.time = time; 1017 record.batteryLevel = (byte) batteryLevel; 1018 return record; 1019 } 1020 assertOnlyHistory(BatteryInfo info)1021 private void assertOnlyHistory(BatteryInfo info) { 1022 mockBatteryStatsHistory(); 1023 UsageView view = mock(UsageView.class); 1024 when(view.getContext()).thenReturn(mContext); 1025 1026 info.bindHistory(view); 1027 verify(view, times(1)).configureGraph(anyInt(), anyInt()); 1028 verify(view, times(1)).addPath(any(SparseIntArray.class)); 1029 verify(view, never()).addProjectedPath(any(SparseIntArray.class)); 1030 } 1031 assertHistoryAndLinearProjection(BatteryInfo info)1032 private void assertHistoryAndLinearProjection(BatteryInfo info) { 1033 mockBatteryStatsHistory(); 1034 UsageView view = mock(UsageView.class); 1035 when(view.getContext()).thenReturn(mContext); 1036 1037 info.bindHistory(view); 1038 verify(view, times(2)).configureGraph(anyInt(), anyInt()); 1039 verify(view, times(1)).addPath(any(SparseIntArray.class)); 1040 ArgumentCaptor<SparseIntArray> pointsActual = ArgumentCaptor.forClass(SparseIntArray.class); 1041 verify(view, times(1)).addProjectedPath(pointsActual.capture()); 1042 1043 // Check that we have two points and the first is correct. 1044 assertThat(pointsActual.getValue().size()).isEqualTo(2); 1045 assertThat(pointsActual.getValue().keyAt(0)).isEqualTo(2000); 1046 assertThat(pointsActual.getValue().valueAt(0)).isEqualTo(97); 1047 } 1048 assertHistoryAndEnhancedProjection(BatteryInfo info)1049 private void assertHistoryAndEnhancedProjection(BatteryInfo info) { 1050 mockBatteryStatsHistory(); 1051 UsageView view = mock(UsageView.class); 1052 when(view.getContext()).thenReturn(mContext); 1053 SparseIntArray pointsExpected = new SparseIntArray(); 1054 pointsExpected.append(2000, 96); 1055 pointsExpected.append(2500, 95); 1056 pointsExpected.append(3000, 94); 1057 doReturn(pointsExpected) 1058 .when(mFeatureFactory.powerUsageFeatureProvider) 1059 .getEnhancedBatteryPredictionCurve(any(Context.class), anyLong()); 1060 1061 info.bindHistory(view); 1062 verify(view, times(2)).configureGraph(anyInt(), anyInt()); 1063 verify(view, times(1)).addPath(any(SparseIntArray.class)); 1064 ArgumentCaptor<SparseIntArray> pointsActual = ArgumentCaptor.forClass(SparseIntArray.class); 1065 verify(view, times(1)).addProjectedPath(pointsActual.capture()); 1066 assertThat(pointsActual.getValue()).isEqualTo(pointsExpected); 1067 } 1068 getBatteryInfo(boolean charging, boolean enhanced, boolean estimate)1069 private BatteryInfo getBatteryInfo(boolean charging, boolean enhanced, boolean estimate) { 1070 if (charging && estimate) { 1071 doReturn(1000L).when(mBatteryUsageStats).getChargeTimeRemainingMs(); 1072 } else { 1073 doReturn(0L).when(mBatteryUsageStats).getChargeTimeRemainingMs(); 1074 } 1075 Estimate batteryEstimate = 1076 new Estimate( 1077 estimate ? 1000 : 0, 1078 false /* isBasedOnUsage */, 1079 1000 /* averageDischargeTime */); 1080 BatteryInfo info = 1081 BatteryInfo.getBatteryInfo( 1082 mContext, 1083 charging ? mChargingBatteryBroadcast : mDisChargingBatteryBroadcast, 1084 mBatteryUsageStats, 1085 batteryEstimate, 1086 SystemClock.elapsedRealtime() * 1000, 1087 false); 1088 doReturn(enhanced) 1089 .when(mFeatureFactory.powerUsageFeatureProvider) 1090 .isEnhancedBatteryPredictionEnabled(mContext); 1091 return info; 1092 } 1093 1094 @Test testBindHistory()1095 public void testBindHistory() { 1096 BatteryInfo info; 1097 1098 info = getBatteryInfo(false /* charging */, false /* enhanced */, false /* estimate */); 1099 assertOnlyHistory(info); 1100 1101 info = getBatteryInfo(false /* charging */, false /* enhanced */, true /* estimate */); 1102 assertHistoryAndLinearProjection(info); 1103 1104 info = getBatteryInfo(false /* charging */, true /* enhanced */, false /* estimate */); 1105 assertOnlyHistory(info); 1106 1107 info = getBatteryInfo(false /* charging */, true /* enhanced */, true /* estimate */); 1108 assertHistoryAndEnhancedProjection(info); 1109 1110 info = getBatteryInfo(true /* charging */, false /* enhanced */, false /* estimate */); 1111 assertOnlyHistory(info); 1112 1113 info = getBatteryInfo(true /* charging */, false /* enhanced */, true /* estimate */); 1114 assertHistoryAndLinearProjection(info); 1115 1116 info = getBatteryInfo(true /* charging */, true /* enhanced */, false /* estimate */); 1117 assertOnlyHistory(info); 1118 1119 // Linear projection for charging even in enhanced mode. 1120 info = getBatteryInfo(true /* charging */, true /* enhanced */, true /* estimate */); 1121 assertHistoryAndLinearProjection(info); 1122 } 1123 } 1124