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.settings.fuelgauge; 17 18 import static com.google.common.truth.Truth.assertThat; 19 20 import static org.mockito.Matchers.any; 21 import static org.mockito.Matchers.anyInt; 22 import static org.mockito.Matchers.eq; 23 import static org.mockito.Mockito.doReturn; 24 import static org.mockito.Mockito.spy; 25 import static org.mockito.Mockito.verify; 26 import static org.mockito.Mockito.when; 27 28 import android.content.Context; 29 import android.content.pm.PackageManager; 30 import android.os.UserManager; 31 import android.support.v7.preference.PreferenceCategory; 32 import android.support.v7.preference.PreferenceGroup; 33 import android.support.v7.preference.PreferenceManager; 34 35 import com.android.internal.os.BatterySipper; 36 import com.android.internal.os.BatterySipper.DrainType; 37 import com.android.internal.os.BatteryStatsHelper; 38 import com.android.settings.R; 39 import com.android.settings.SettingsRobolectricTestRunner; 40 import com.android.settings.TestConfig; 41 import com.android.settings.Utils; 42 import com.android.settings.fuelgauge.PowerUsageAdvanced.PowerUsageData; 43 import com.android.settings.fuelgauge.PowerUsageAdvanced.PowerUsageData.UsageType; 44 45 import org.junit.Before; 46 import org.junit.Test; 47 import org.junit.runner.RunWith; 48 import org.mockito.Answers; 49 import org.mockito.Mock; 50 import org.mockito.MockitoAnnotations; 51 import org.robolectric.RuntimeEnvironment; 52 import org.robolectric.annotation.Config; 53 54 import java.util.ArrayList; 55 import java.util.Collections; 56 import java.util.List; 57 58 @RunWith(SettingsRobolectricTestRunner.class) 59 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) 60 public class PowerUsageAdvancedTest { 61 private static final int FAKE_UID_1 = 50; 62 private static final int FAKE_UID_2 = 100; 63 private static final int DISCHARGE_AMOUNT = 60; 64 private static final double TYPE_APP_USAGE = 80; 65 private static final double TYPE_BLUETOOTH_USAGE = 50; 66 private static final double TYPE_WIFI_USAGE = 0; 67 private static final double TOTAL_USAGE = TYPE_APP_USAGE * 2 + TYPE_BLUETOOTH_USAGE 68 + TYPE_WIFI_USAGE; 69 private static final double TOTAL_POWER = 500; 70 private static final double PRECISION = 0.001; 71 private static final String STUB_STRING = "stub_string"; 72 @Mock 73 private BatterySipper mNormalBatterySipper; 74 @Mock 75 private BatterySipper mMaxBatterySipper; 76 @Mock(answer = Answers.RETURNS_DEEP_STUBS) 77 private BatteryStatsHelper mBatteryStatsHelper; 78 @Mock 79 private PowerUsageFeatureProvider mPowerUsageFeatureProvider; 80 @Mock 81 private PackageManager mPackageManager; 82 @Mock 83 private UserManager mUserManager; 84 private PowerUsageAdvanced mPowerUsageAdvanced; 85 private PowerUsageData mPowerUsageData; 86 private Context mShadowContext; 87 88 @Before setUp()89 public void setUp() { 90 MockitoAnnotations.initMocks(this); 91 mShadowContext = RuntimeEnvironment.application; 92 mPowerUsageAdvanced = spy(new PowerUsageAdvanced()); 93 94 List<BatterySipper> batterySippers = new ArrayList<>(); 95 batterySippers.add(new BatterySipper(DrainType.APP, 96 new FakeUid(FAKE_UID_1), TYPE_APP_USAGE)); 97 batterySippers.add(new BatterySipper(DrainType.APP, 98 new FakeUid(FAKE_UID_2), TYPE_APP_USAGE)); 99 batterySippers.add(new BatterySipper(DrainType.BLUETOOTH, new FakeUid(FAKE_UID_1), 100 TYPE_BLUETOOTH_USAGE)); 101 batterySippers.add(new BatterySipper(DrainType.WIFI, new FakeUid(FAKE_UID_1), 102 TYPE_WIFI_USAGE)); 103 104 when(mBatteryStatsHelper.getStats().getDischargeAmount(anyInt())).thenReturn( 105 DISCHARGE_AMOUNT); 106 when(mBatteryStatsHelper.getUsageList()).thenReturn(batterySippers); 107 when(mBatteryStatsHelper.getTotalPower()).thenReturn(TOTAL_USAGE); 108 when(mPowerUsageAdvanced.getContext()).thenReturn(mShadowContext); 109 doReturn(STUB_STRING).when(mPowerUsageAdvanced).getString(anyInt(), any(), any()); 110 doReturn(STUB_STRING).when(mPowerUsageAdvanced).getString(anyInt(), any()); 111 doReturn(mShadowContext.getText(R.string.battery_used_for)).when( 112 mPowerUsageAdvanced).getText(R.string.battery_used_for); 113 mPowerUsageAdvanced.setPackageManager(mPackageManager); 114 mPowerUsageAdvanced.setPowerUsageFeatureProvider(mPowerUsageFeatureProvider); 115 mPowerUsageAdvanced.setUserManager(mUserManager); 116 mPowerUsageAdvanced.setBatteryUtils(BatteryUtils.getInstance(mShadowContext)); 117 118 mPowerUsageData = new PowerUsageData(UsageType.APP); 119 mMaxBatterySipper.totalPowerMah = TYPE_BLUETOOTH_USAGE; 120 mMaxBatterySipper.drainType = DrainType.BLUETOOTH; 121 mNormalBatterySipper.drainType = DrainType.SCREEN; 122 } 123 124 @Test testPrefs_shouldNotBeSelectable()125 public void testPrefs_shouldNotBeSelectable() { 126 PreferenceManager pm = new PreferenceManager(mShadowContext); 127 when(mPowerUsageAdvanced.getPreferenceManager()).thenReturn(pm); 128 PreferenceGroup prefGroup = spy(new PreferenceCategory(mShadowContext)); 129 when(prefGroup.getPreferenceManager()).thenReturn(pm); 130 131 mPowerUsageAdvanced.refreshPowerUsageDataList(mBatteryStatsHelper, prefGroup); 132 assertThat(prefGroup.getPreferenceCount()).isAtLeast(1); 133 for (int i = 0, count = prefGroup.getPreferenceCount(); i < count; i++) { 134 PowerGaugePreference pref = (PowerGaugePreference) prefGroup.getPreference(i); 135 assertThat(pref.isSelectable()).isFalse(); 136 } 137 } 138 139 @Test testExtractUsageType_TypeSystem_ReturnSystem()140 public void testExtractUsageType_TypeSystem_ReturnSystem() { 141 mNormalBatterySipper.drainType = DrainType.APP; 142 when(mPowerUsageFeatureProvider.isTypeSystem(any())).thenReturn(true); 143 144 assertThat(mPowerUsageAdvanced.extractUsageType(mNormalBatterySipper)) 145 .isEqualTo(UsageType.SYSTEM); 146 } 147 148 @Test testExtractUsageType_TypeEqualsToDrainType_ReturnRelevantType()149 public void testExtractUsageType_TypeEqualsToDrainType_ReturnRelevantType() { 150 final DrainType drainTypes[] = {DrainType.WIFI, DrainType.BLUETOOTH, DrainType.IDLE, 151 DrainType.USER, DrainType.CELL, DrainType.UNACCOUNTED}; 152 final int usageTypes[] = {UsageType.WIFI, UsageType.BLUETOOTH, UsageType.IDLE, 153 UsageType.USER, UsageType.CELL, UsageType.UNACCOUNTED}; 154 155 assertThat(drainTypes.length).isEqualTo(usageTypes.length); 156 for (int i = 0, size = drainTypes.length; i < size; i++) { 157 mNormalBatterySipper.drainType = drainTypes[i]; 158 assertThat(mPowerUsageAdvanced.extractUsageType(mNormalBatterySipper)) 159 .isEqualTo(usageTypes[i]); 160 } 161 } 162 163 @Test testExtractUsageType_TypeService_ReturnSystem()164 public void testExtractUsageType_TypeService_ReturnSystem() { 165 mNormalBatterySipper.drainType = DrainType.APP; 166 when(mNormalBatterySipper.getUid()).thenReturn(FAKE_UID_1); 167 when(mPowerUsageFeatureProvider.isTypeService(any())).thenReturn(true); 168 169 assertThat(mPowerUsageAdvanced.extractUsageType(mNormalBatterySipper)) 170 .isEqualTo(UsageType.SYSTEM); 171 } 172 173 @Test testParsePowerUsageData_PercentageCalculatedCorrectly()174 public void testParsePowerUsageData_PercentageCalculatedCorrectly() { 175 final double percentApp = TYPE_APP_USAGE * 2 / TOTAL_USAGE * DISCHARGE_AMOUNT; 176 final double percentWifi = TYPE_WIFI_USAGE / TOTAL_USAGE * DISCHARGE_AMOUNT; 177 final double percentBluetooth = TYPE_BLUETOOTH_USAGE / TOTAL_USAGE * DISCHARGE_AMOUNT; 178 179 List<PowerUsageData> batteryData = 180 mPowerUsageAdvanced.parsePowerUsageData(mBatteryStatsHelper); 181 for (PowerUsageData data : batteryData) { 182 switch (data.usageType) { 183 case UsageType.WIFI: 184 assertThat(data.percentage).isWithin(PRECISION).of(percentWifi); 185 break; 186 case UsageType.APP: 187 assertThat(data.percentage).isWithin(PRECISION).of(percentApp); 188 break; 189 case UsageType.BLUETOOTH: 190 assertThat(data.percentage).isWithin(PRECISION).of(percentBluetooth); 191 break; 192 default: 193 break; 194 } 195 } 196 } 197 198 @Test testUpdateUsageDataSummary_onlyOneApp_showUsageTime()199 public void testUpdateUsageDataSummary_onlyOneApp_showUsageTime() { 200 final String expectedSummary = "Used for 0m"; 201 mPowerUsageData.usageList.add(mNormalBatterySipper); 202 203 mPowerUsageAdvanced.updateUsageDataSummary(mPowerUsageData, TOTAL_POWER, DISCHARGE_AMOUNT); 204 205 assertThat(mPowerUsageData.summary.toString()).isEqualTo(expectedSummary); 206 } 207 208 @Test testUpdateUsageDataSummary_typeIdle_showUsageTime()209 public void testUpdateUsageDataSummary_typeIdle_showUsageTime() { 210 mPowerUsageData.usageType = UsageType.IDLE; 211 mPowerUsageData.usageList.add(mNormalBatterySipper); 212 213 mPowerUsageAdvanced.updateUsageDataSummary(mPowerUsageData, TOTAL_POWER, DISCHARGE_AMOUNT); 214 215 assertThat(mPowerUsageData.summary.toString()).isEqualTo("0m"); 216 } 217 218 @Test testUpdateUsageDataSummary_moreThanOneApp_showMaxUsageApp()219 public void testUpdateUsageDataSummary_moreThanOneApp_showMaxUsageApp() { 220 mPowerUsageData.usageList.add(mNormalBatterySipper); 221 mPowerUsageData.usageList.add(mMaxBatterySipper); 222 doReturn(mMaxBatterySipper).when(mPowerUsageAdvanced).findBatterySipperWithMaxBatteryUsage( 223 mPowerUsageData.usageList); 224 final double percentage = (TYPE_BLUETOOTH_USAGE / TOTAL_POWER) * DISCHARGE_AMOUNT; 225 mPowerUsageAdvanced.updateUsageDataSummary(mPowerUsageData, TOTAL_POWER, DISCHARGE_AMOUNT); 226 227 verify(mPowerUsageAdvanced).getString(eq(R.string.battery_used_by), 228 eq(Utils.formatPercentage(percentage, true)), any()); 229 } 230 231 @Test testFindBatterySipperWithMaxBatteryUsage_findCorrectOne()232 public void testFindBatterySipperWithMaxBatteryUsage_findCorrectOne() { 233 mPowerUsageData.usageList.add(mNormalBatterySipper); 234 mPowerUsageData.usageList.add(mMaxBatterySipper); 235 BatterySipper sipper = mPowerUsageAdvanced.findBatterySipperWithMaxBatteryUsage( 236 mPowerUsageData.usageList); 237 238 assertThat(sipper).isEqualTo(mMaxBatterySipper); 239 } 240 241 @Test testInit_ContainsAllUsageType()242 public void testInit_ContainsAllUsageType() { 243 final int[] usageTypeSet = mPowerUsageAdvanced.mUsageTypes; 244 245 assertThat(usageTypeSet).asList().containsExactly(UsageType.APP, UsageType.WIFI, 246 UsageType.CELL, UsageType.BLUETOOTH, UsageType.IDLE, UsageType.USER, 247 UsageType.SYSTEM, UsageType.UNACCOUNTED, UsageType.OVERCOUNTED); 248 } 249 250 @Test testPowerUsageData_SortedByUsage()251 public void testPowerUsageData_SortedByUsage() { 252 List<PowerUsageData> dataList = new ArrayList<>(); 253 254 dataList.add(new PowerUsageData(UsageType.WIFI, TYPE_WIFI_USAGE)); 255 dataList.add(new PowerUsageData(UsageType.BLUETOOTH, TYPE_BLUETOOTH_USAGE)); 256 dataList.add(new PowerUsageData(UsageType.APP, TYPE_APP_USAGE)); 257 Collections.sort(dataList); 258 259 for (int i = 1, size = dataList.size(); i < size; i++) { 260 assertThat(dataList.get(i - 1).totalPowerMah).isAtLeast(dataList.get(i).totalPowerMah); 261 } 262 } 263 264 @Test testShouldHideCategory_typeUnAccounted_returnTrue()265 public void testShouldHideCategory_typeUnAccounted_returnTrue() { 266 mPowerUsageData.usageType = UsageType.UNACCOUNTED; 267 268 assertThat(mPowerUsageAdvanced.shouldHideCategory(mPowerUsageData)).isTrue(); 269 } 270 271 @Test testShouldHideCategory_typeOverCounted_returnTrue()272 public void testShouldHideCategory_typeOverCounted_returnTrue() { 273 mPowerUsageData.usageType = UsageType.OVERCOUNTED; 274 275 assertThat(mPowerUsageAdvanced.shouldHideCategory(mPowerUsageData)).isTrue(); 276 } 277 278 @Test testShouldHideCategory_typeUserAndOnlyOne_returnTrue()279 public void testShouldHideCategory_typeUserAndOnlyOne_returnTrue() { 280 mPowerUsageData.usageType = UsageType.USER; 281 doReturn(1).when(mUserManager).getUserCount(); 282 283 assertThat(mPowerUsageAdvanced.shouldHideCategory(mPowerUsageData)).isTrue(); 284 } 285 286 @Test testShouldHideCategory_typeUserAndMoreThanOne_returnFalse()287 public void testShouldHideCategory_typeUserAndMoreThanOne_returnFalse() { 288 mPowerUsageData.usageType = UsageType.USER; 289 doReturn(2).when(mUserManager).getUserCount(); 290 291 assertThat(mPowerUsageAdvanced.shouldHideCategory(mPowerUsageData)).isFalse(); 292 } 293 294 @Test testShouldHideCategory_typeNormal_returnFalse()295 public void testShouldHideCategory_typeNormal_returnFalse() { 296 mPowerUsageData.usageType = UsageType.APP; 297 298 assertThat(mPowerUsageAdvanced.shouldHideCategory(mPowerUsageData)).isFalse(); 299 } 300 301 @Test testShouldHideSummary_typeCell_returnTrue()302 public void testShouldHideSummary_typeCell_returnTrue() { 303 mPowerUsageData.usageType = UsageType.CELL; 304 305 assertThat(mPowerUsageAdvanced.shouldHideSummary(mPowerUsageData)).isTrue(); 306 } 307 308 @Test testShouldHideSummary_typeWifi_returnTrue()309 public void testShouldHideSummary_typeWifi_returnTrue() { 310 mPowerUsageData.usageType = UsageType.WIFI; 311 312 assertThat(mPowerUsageAdvanced.shouldHideSummary(mPowerUsageData)).isTrue(); 313 } 314 315 @Test testShouldHideSummary_typeBluetooth_returnTrue()316 public void testShouldHideSummary_typeBluetooth_returnTrue() { 317 mPowerUsageData.usageType = UsageType.BLUETOOTH; 318 319 assertThat(mPowerUsageAdvanced.shouldHideSummary(mPowerUsageData)).isTrue(); 320 } 321 322 @Test testShouldHideSummary_typeNormal_returnFalse()323 public void testShouldHideSummary_typeNormal_returnFalse() { 324 mPowerUsageData.usageType = UsageType.APP; 325 326 assertThat(mPowerUsageAdvanced.shouldHideSummary(mPowerUsageData)).isFalse(); 327 } 328 329 @Test testShouldShowBatterySipper_typeScreen_returnFalse()330 public void testShouldShowBatterySipper_typeScreen_returnFalse() { 331 mNormalBatterySipper.drainType = DrainType.SCREEN; 332 333 assertThat(mPowerUsageAdvanced.shouldShowBatterySipper(mNormalBatterySipper)).isFalse(); 334 } 335 336 @Test testShouldShowBatterySipper_typeNormal_returnTrue()337 public void testShouldShowBatterySipper_typeNormal_returnTrue() { 338 mNormalBatterySipper.drainType = DrainType.APP; 339 340 assertThat(mPowerUsageAdvanced.shouldShowBatterySipper(mNormalBatterySipper)).isTrue(); 341 } 342 343 @Test testCalculateHiddenPower_returnCorrectPower()344 public void testCalculateHiddenPower_returnCorrectPower() { 345 List<PowerUsageData> powerUsageDataList = new ArrayList<>(); 346 final double unaccountedPower = 100; 347 final double normalPower = 150; 348 powerUsageDataList.add(new PowerUsageData(UsageType.UNACCOUNTED, unaccountedPower)); 349 powerUsageDataList.add(new PowerUsageData(UsageType.APP, normalPower)); 350 powerUsageDataList.add(new PowerUsageData(UsageType.CELL, normalPower)); 351 352 assertThat(mPowerUsageAdvanced.calculateHiddenPower(powerUsageDataList)).isWithin( 353 PRECISION).of(unaccountedPower); 354 } 355 } 356