2 * Copyright (C) 2017 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com.android.settings.fuelgauge;
18 import android.content.Context;
19 import android.os.BatteryStats;
20 import android.os.Process;
21 import android.text.format.DateUtils;
23 import com.android.internal.os.BatterySipper;
24 import com.android.internal.os.BatteryStatsHelper;
25 import com.android.settings.SettingsRobolectricTestRunner;
26 import com.android.settings.TestConfig;
27 import com.android.settings.testutils.FakeFeatureFactory;
29 import org.junit.Before;
30 import org.junit.Test;
31 import org.junit.runner.RunWith;
32 import org.mockito.Answers;
33 import org.mockito.Mock;
34 import org.mockito.MockitoAnnotations;
35 import org.robolectric.RuntimeEnvironment;
36 import org.robolectric.annotation.Config;
38 import java.util.ArrayList;
39 import java.util.List;
41 import static android.os.BatteryStats.Uid.PROCESS_STATE_BACKGROUND;
42 import static android.os.BatteryStats.Uid.PROCESS_STATE_FOREGROUND;
43 import static android.os.BatteryStats.Uid.PROCESS_STATE_FOREGROUND_SERVICE;
44 import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP;
45 import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP_SLEEPING;
47 import static com.google.common.truth.Truth.assertThat;
49 import static org.mockito.Matchers.any;
50 import static org.mockito.Matchers.anyInt;
51 import static org.mockito.Matchers.anyLong;
52 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
53 import static org.mockito.Mockito.doNothing;
54 import static org.mockito.Mockito.doReturn;
55 import static org.mockito.Matchers.eq;
56 import static org.mockito.Mockito.mock;
57 import static org.mockito.Mockito.when;
58 import static org.mockito.Mockito.spy;
60 @RunWith(SettingsRobolectricTestRunner.class)
61 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
62 public class BatteryUtilsTest {
63 // unit that used to converted ms to us
64 private static final long UNIT = 1000;
65 private static final long TIME_STATE_TOP = 1500 * UNIT;
66 private static final long TIME_STATE_FOREGROUND_SERVICE = 2000 * UNIT;
67 private static final long TIME_STATE_TOP_SLEEPING = 2500 * UNIT;
68 private static final long TIME_STATE_FOREGROUND = 3000 * UNIT;
69 private static final long TIME_STATE_BACKGROUND = 6000 * UNIT;
70 private static final long TIME_FOREGROUND_ACTIVITY_ZERO = 0;
71 private static final long TIME_FOREGROUND_ACTIVITY = 100 * DateUtils.MINUTE_IN_MILLIS;
72 private static final long TIME_SINCE_LAST_FULL_CHARGE_MS = 120 * 60 * 1000;
74 private static final int UID = 123;
75 private static final long TIME_EXPECTED_FOREGROUND = 1500;
76 private static final long TIME_EXPECTED_BACKGROUND = 6000;
77 private static final long TIME_EXPECTED_ALL = 7500;
78 private static final double BATTERY_SCREEN_USAGE = 300;
79 private static final double BATTERY_SYSTEM_USAGE = 600;
80 private static final double BATTERY_OVERACCOUNTED_USAGE = 500;
81 private static final double BATTERY_UNACCOUNTED_USAGE = 700;
82 private static final double BATTERY_APP_USAGE = 100;
83 private static final double TOTAL_BATTERY_USAGE = 1000;
84 private static final double HIDDEN_USAGE = 200;
85 private static final int DISCHARGE_AMOUNT = 80;
86 private static final double PERCENT_SYSTEM_USAGE = 60;
87 private static final double PRECISION = 0.001;
90 private BatteryStats.Uid mUid;
92 private BatterySipper mNormalBatterySipper;
94 private BatterySipper mScreenBatterySipper;
96 private BatterySipper mOvercountedBatterySipper;
98 private BatterySipper mUnaccountedBatterySipper;
100 private BatterySipper mSystemBatterySipper;
102 private BatterySipper mCellBatterySipper;
103 @Mock(answer = Answers.RETURNS_DEEP_STUBS)
104 private Context mContext;
105 @Mock(answer = Answers.RETURNS_DEEP_STUBS)
106 private BatteryStatsHelper mBatteryStatsHelper;
107 private BatteryUtils mBatteryUtils;
108 private FakeFeatureFactory mFeatureFactory;
109 private PowerUsageFeatureProvider mProvider;
112 public void setUp() {
113 MockitoAnnotations.initMocks(this);
115 FakeFeatureFactory.setupForTest(mContext);
116 mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
117 mProvider = mFeatureFactory.powerUsageFeatureProvider;
119 doReturn(TIME_STATE_TOP).when(mUid).getProcessStateTime(eq(PROCESS_STATE_TOP), anyLong(),
121 doReturn(TIME_STATE_FOREGROUND_SERVICE).when(mUid).getProcessStateTime(
122 eq(PROCESS_STATE_FOREGROUND_SERVICE), anyLong(), anyInt());
123 doReturn(TIME_STATE_TOP_SLEEPING).when(mUid).getProcessStateTime(
124 eq(PROCESS_STATE_TOP_SLEEPING), anyLong(), anyInt());
125 doReturn(TIME_STATE_FOREGROUND).when(mUid).getProcessStateTime(eq(PROCESS_STATE_FOREGROUND),
126 anyLong(), anyInt());
127 doReturn(TIME_STATE_BACKGROUND).when(mUid).getProcessStateTime(eq(PROCESS_STATE_BACKGROUND),
128 anyLong(), anyInt());
130 mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
131 mNormalBatterySipper.totalPowerMah = TOTAL_BATTERY_USAGE;
133 mScreenBatterySipper.drainType = BatterySipper.DrainType.SCREEN;
134 mScreenBatterySipper.totalPowerMah = BATTERY_SCREEN_USAGE;
136 mSystemBatterySipper.drainType = BatterySipper.DrainType.APP;
137 mSystemBatterySipper.totalPowerMah = BATTERY_SYSTEM_USAGE;
138 when(mSystemBatterySipper.getUid()).thenReturn(Process.SYSTEM_UID);
140 mOvercountedBatterySipper.drainType = BatterySipper.DrainType.OVERCOUNTED;
141 mOvercountedBatterySipper.totalPowerMah = BATTERY_OVERACCOUNTED_USAGE;
143 mUnaccountedBatterySipper.drainType = BatterySipper.DrainType.UNACCOUNTED;
144 mUnaccountedBatterySipper.totalPowerMah = BATTERY_UNACCOUNTED_USAGE;
146 mBatteryUtils = BatteryUtils.getInstance(RuntimeEnvironment.application);
147 mBatteryUtils.mPowerUsageFeatureProvider = mProvider;
149 mBatteryUtils = spy(new BatteryUtils(RuntimeEnvironment.application));
153 public void testGetProcessTimeMs_typeForeground_timeCorrect() {
154 final long time = mBatteryUtils.getProcessTimeMs(BatteryUtils.StatusType.FOREGROUND, mUid,
155 BatteryStats.STATS_SINCE_CHARGED);
157 assertThat(time).isEqualTo(TIME_EXPECTED_FOREGROUND);
161 public void testGetProcessTimeMs_typeBackground_timeCorrect() {
162 final long time = mBatteryUtils.getProcessTimeMs(BatteryUtils.StatusType.BACKGROUND, mUid,
163 BatteryStats.STATS_SINCE_CHARGED);
165 assertThat(time).isEqualTo(TIME_EXPECTED_BACKGROUND);
169 public void testGetProcessTimeMs_typeAll_timeCorrect() {
170 final long time = mBatteryUtils.getProcessTimeMs(BatteryUtils.StatusType.ALL, mUid,
171 BatteryStats.STATS_SINCE_CHARGED);
173 assertThat(time).isEqualTo(TIME_EXPECTED_ALL);
177 public void testGetProcessTimeMs_uidNull_returnZero() {
178 final long time = mBatteryUtils.getProcessTimeMs(BatteryUtils.StatusType.ALL, null,
179 BatteryStats.STATS_SINCE_CHARGED);
181 assertThat(time).isEqualTo(0);
185 public void testRemoveHiddenBatterySippers_ContainsHiddenSippers_RemoveAndReturnValue() {
186 final List<BatterySipper> sippers = new ArrayList<>();
187 sippers.add(mNormalBatterySipper);
188 sippers.add(mScreenBatterySipper);
189 sippers.add(mSystemBatterySipper);
190 sippers.add(mOvercountedBatterySipper);
191 sippers.add(mUnaccountedBatterySipper);
192 when(mProvider.isTypeSystem(mSystemBatterySipper))
194 doNothing().when(mBatteryUtils).smearScreenBatterySipper(any(), any());
196 final double totalUsage = mBatteryUtils.removeHiddenBatterySippers(sippers);
198 assertThat(sippers).containsExactly(mNormalBatterySipper);
199 assertThat(totalUsage).isWithin(PRECISION).of(BATTERY_SYSTEM_USAGE);
203 public void testShouldHideSipper_TypeUnAccounted_ReturnTrue() {
204 mNormalBatterySipper.drainType = BatterySipper.DrainType.UNACCOUNTED;
205 assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
209 public void testShouldHideSipper_TypeOverAccounted_ReturnTrue() {
210 mNormalBatterySipper.drainType = BatterySipper.DrainType.OVERCOUNTED;
211 assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
215 public void testShouldHideSipper_TypeIdle_ReturnTrue() {
216 mNormalBatterySipper.drainType = BatterySipper.DrainType.IDLE;
217 assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
221 public void testShouldHideSipper_TypeCell_ReturnTrue() {
222 mNormalBatterySipper.drainType = BatterySipper.DrainType.CELL;
223 assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
227 public void testShouldHideSipper_TypeScreen_ReturnTrue() {
228 mNormalBatterySipper.drainType = BatterySipper.DrainType.SCREEN;
229 assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
233 public void testShouldHideSipper_TypeSystem_ReturnTrue() {
234 mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
235 when(mNormalBatterySipper.getUid()).thenReturn(Process.ROOT_UID);
236 when(mProvider.isTypeSystem(any())).thenReturn(true);
237 assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
241 public void testShouldHideSipper_UidNormal_ReturnFalse() {
242 mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
243 when(mNormalBatterySipper.getUid()).thenReturn(UID);
244 assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isFalse();
248 public void testShouldHideSipper_TypeService_ReturnTrue() {
249 mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
250 when(mNormalBatterySipper.getUid()).thenReturn(UID);
251 when(mProvider.isTypeService(any())).thenReturn(true);
253 assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue();
257 public void testCalculateBatteryPercent() {
258 assertThat(mBatteryUtils.calculateBatteryPercent(BATTERY_SYSTEM_USAGE, TOTAL_BATTERY_USAGE,
259 HIDDEN_USAGE, DISCHARGE_AMOUNT))
260 .isWithin(PRECISION).of(PERCENT_SYSTEM_USAGE);
264 public void testSmearScreenBatterySipper() {
265 final BatterySipper sipperNull = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY_ZERO,
266 BATTERY_APP_USAGE, 0 /* uid */, true /* isUidNull */);
267 final BatterySipper sipperBg = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY_ZERO,
268 BATTERY_APP_USAGE, 1 /* uid */, false /* isUidNull */);
269 final BatterySipper sipperFg = createTestSmearBatterySipper(TIME_FOREGROUND_ACTIVITY,
270 BATTERY_APP_USAGE, 2 /* uid */, false /* isUidNull */);
272 final List<BatterySipper> sippers = new ArrayList<>();
273 sippers.add(sipperNull);
274 sippers.add(sipperBg);
275 sippers.add(sipperFg);
277 mBatteryUtils.smearScreenBatterySipper(sippers, mScreenBatterySipper);
279 assertThat(sipperNull.totalPowerMah).isWithin(PRECISION).of(BATTERY_APP_USAGE);
280 assertThat(sipperBg.totalPowerMah).isWithin(PRECISION).of(BATTERY_APP_USAGE);
281 assertThat(sipperFg.totalPowerMah).isWithin(PRECISION).of(
282 BATTERY_APP_USAGE + BATTERY_SCREEN_USAGE);
286 public void testSortUsageList() {
287 final List<BatterySipper> sippers = new ArrayList<>();
288 sippers.add(mNormalBatterySipper);
289 sippers.add(mScreenBatterySipper);
290 sippers.add(mSystemBatterySipper);
292 mBatteryUtils.sortUsageList(sippers);
294 assertThat(sippers).containsExactly(mNormalBatterySipper, mSystemBatterySipper,
295 mScreenBatterySipper);
299 public void testCalculateLastFullChargeTime() {
300 final long currentTimeMs = System.currentTimeMillis();
301 when(mBatteryStatsHelper.getStats().getStartClockTime()).thenReturn(
302 currentTimeMs - TIME_SINCE_LAST_FULL_CHARGE_MS);
304 assertThat(mBatteryUtils.calculateLastFullChargeTime(
305 mBatteryStatsHelper, currentTimeMs)).isEqualTo(TIME_SINCE_LAST_FULL_CHARGE_MS);
308 private BatterySipper createTestSmearBatterySipper(long activityTime, double totalPowerMah,
309 int uidCode, boolean isUidNull) {
310 final BatterySipper sipper = mock(BatterySipper.class);
311 sipper.drainType = BatterySipper.DrainType.APP;
312 sipper.totalPowerMah = totalPowerMah;
313 doReturn(uidCode).when(sipper).getUid();
315 final BatteryStats.Uid uid = mock(BatteryStats.Uid.class, RETURNS_DEEP_STUBS);
316 doReturn(activityTime).when(mBatteryUtils).getForegroundActivityTotalTimeMs(eq(uid),
318 doReturn(uidCode).when(uid).getUid();