blob: f51e4731a390b8b165a4953d4d3d6405fb36b4b4 [file] [log] [blame]
Jason Monkd819c312017-08-11 12:53:36 -04001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5 * except in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the
10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11 * KIND, either express or implied. See the License for the specific language governing
12 * permissions and limitations under the License.
13 */
14
15package com.android.systemui.power;
16
Jason Monkd819c312017-08-11 12:53:36 -040017import static android.provider.Settings.Global.SHOW_TEMPERATURE_WARNING;
Sherry Huangce02ed32019-01-17 20:37:29 +080018import static android.provider.Settings.Global.SHOW_USB_TEMPERATURE_ALARM;
Jason Monkd819c312017-08-11 12:53:36 -040019
Salvador Martinez4387bd52019-02-21 16:16:28 -080020import static com.google.common.truth.Truth.assertThat;
Amin Shaikh2f6c45c2018-04-16 14:00:09 -040021
Sherry Huangce02ed32019-01-17 20:37:29 +080022import static org.mockito.Matchers.eq;
23import static org.mockito.Mockito.anyObject;
Jason Monkd819c312017-08-11 12:53:36 -040024import static org.mockito.Mockito.mock;
25import static org.mockito.Mockito.never;
Salvador Martinez926f0712018-07-03 18:07:07 -070026import static org.mockito.Mockito.times;
Jason Monkd819c312017-08-11 12:53:36 -040027import static org.mockito.Mockito.verify;
28import static org.mockito.Mockito.when;
29
30import android.content.Context;
Salvador Martinezf9e47502018-01-04 13:45:48 -080031import android.os.BatteryManager;
Sherry Huangce02ed32019-01-17 20:37:29 +080032import android.os.IThermalEventListener;
Wei Wangbf05e602018-11-21 11:46:48 -080033import android.os.IThermalService;
Amin Shaikh2f6c45c2018-04-16 14:00:09 -040034import android.os.PowerManager;
Sherry Huangce02ed32019-01-17 20:37:29 +080035import android.os.Temperature;
Jason Monkd819c312017-08-11 12:53:36 -040036import android.provider.Settings;
Wei Wangbf05e602018-11-21 11:46:48 -080037import android.test.suitebuilder.annotation.SmallTest;
Jason Monkd819c312017-08-11 12:53:36 -040038import android.testing.AndroidTestingRunner;
Wei Wangfeb9de62018-11-26 14:35:17 -080039import android.testing.TestableLooper;
Jason Monkd819c312017-08-11 12:53:36 -040040import android.testing.TestableLooper.RunWithLooper;
41import android.testing.TestableResources;
Jason Monkd819c312017-08-11 12:53:36 -040042
43import com.android.systemui.R;
44import com.android.systemui.SysuiTestCase;
45import com.android.systemui.power.PowerUI.WarningsUI;
46import com.android.systemui.statusbar.phone.StatusBar;
47
Salvador Martinez4387bd52019-02-21 16:16:28 -080048import java.time.Duration;
49import java.util.concurrent.TimeUnit;
50
Jason Monkd819c312017-08-11 12:53:36 -040051import org.junit.Before;
52import org.junit.Test;
53import org.junit.runner.RunWith;
Amin Shaikh2f6c45c2018-04-16 14:00:09 -040054import org.mockito.Mock;
55import org.mockito.MockitoAnnotations;
Jason Monkd819c312017-08-11 12:53:36 -040056
57@RunWith(AndroidTestingRunner.class)
58@RunWithLooper
59@SmallTest
60public class PowerUITest extends SysuiTestCase {
61
Salvador Martinezf9e47502018-01-04 13:45:48 -080062 private static final boolean UNPLUGGED = false;
63 private static final boolean POWER_SAVER_OFF = false;
64 private static final int ABOVE_WARNING_BUCKET = 1;
Salvador Martinezbb902fc2018-01-22 19:46:55 -080065 private static final long ONE_HOUR_MILLIS = Duration.ofHours(1).toMillis();
Salvador Martinezf9e47502018-01-04 13:45:48 -080066 public static final int BELOW_WARNING_BUCKET = -1;
67 public static final long BELOW_HYBRID_THRESHOLD = TimeUnit.HOURS.toMillis(2);
Salvador Martinez88b0d502018-10-01 11:31:43 -070068 public static final long BELOW_SEVERE_HYBRID_THRESHOLD = TimeUnit.MINUTES.toMillis(30);
Salvador Martinezf9e47502018-01-04 13:45:48 -080069 public static final long ABOVE_HYBRID_THRESHOLD = TimeUnit.HOURS.toMillis(4);
Salvador Martinezfd38aa52018-03-28 23:56:59 -070070 private static final long ABOVE_CHARGE_CYCLE_THRESHOLD = Duration.ofHours(8).toMillis();
Salvador Martinez926f0712018-07-03 18:07:07 -070071 private static final int OLD_BATTERY_LEVEL_NINE = 9;
72 private static final int OLD_BATTERY_LEVEL_10 = 10;
Salvador Martinez88b0d502018-10-01 11:31:43 -070073 private static final long VERY_BELOW_SEVERE_HYBRID_THRESHOLD = TimeUnit.MINUTES.toMillis(15);
Salvador Martinez4387bd52019-02-21 16:16:28 -080074 public static final int BATTERY_LEVEL_10 = 10;
Jason Monkd819c312017-08-11 12:53:36 -040075 private WarningsUI mMockWarnings;
76 private PowerUI mPowerUI;
Salvador Martinezbb902fc2018-01-22 19:46:55 -080077 private EnhancedEstimates mEnhancedEstimates;
Amin Shaikh2f6c45c2018-04-16 14:00:09 -040078 @Mock private PowerManager mPowerManager;
Wei Wangbf05e602018-11-21 11:46:48 -080079 @Mock private IThermalService mThermalServiceMock;
Sherry Huangce02ed32019-01-17 20:37:29 +080080 private IThermalEventListener mThermalEventUsbListener;
81 private IThermalEventListener mThermalEventSkinListener;
Jason Monkd819c312017-08-11 12:53:36 -040082
83 @Before
84 public void setup() {
Amin Shaikh2f6c45c2018-04-16 14:00:09 -040085 MockitoAnnotations.initMocks(this);
Jason Monkd819c312017-08-11 12:53:36 -040086 mMockWarnings = mDependency.injectMockDependency(WarningsUI.class);
Salvador Martinezbb902fc2018-01-22 19:46:55 -080087 mEnhancedEstimates = mDependency.injectMockDependency(EnhancedEstimates.class);
Salvador Martinezf9e47502018-01-04 13:45:48 -080088
Jason Monkd819c312017-08-11 12:53:36 -040089 mContext.putComponent(StatusBar.class, mock(StatusBar.class));
Amin Shaikh2f6c45c2018-04-16 14:00:09 -040090 mContext.addMockSystemService(Context.POWER_SERVICE, mPowerManager);
Jason Monkd819c312017-08-11 12:53:36 -040091
92 createPowerUi();
Sherry Huangce02ed32019-01-17 20:37:29 +080093 mThermalEventSkinListener = mPowerUI.new ThermalEventSkinListener();
94 mThermalEventUsbListener = mPowerUI.new ThermalEventUsbListener();
Jason Monkd819c312017-08-11 12:53:36 -040095 }
96
97 @Test
Sherry Huangce02ed32019-01-17 20:37:29 +080098 public void testSkinWarning_throttlingCritical() throws Exception {
Jason Monkd819c312017-08-11 12:53:36 -040099 mPowerUI.start();
Jason Monkd819c312017-08-11 12:53:36 -0400100
Sherry Huangce02ed32019-01-17 20:37:29 +0800101 final Temperature temp = getCriticalStatusTemp(Temperature.TYPE_SKIN, "skin1");
102 mThermalEventSkinListener.notifyThrottling(temp);
Jason Monkd819c312017-08-11 12:53:36 -0400103
Sherry Huangce02ed32019-01-17 20:37:29 +0800104 // dismiss skin high temperature warning when throttling status is critical
Wei Wangfeb9de62018-11-26 14:35:17 -0800105 TestableLooper.get(this).processAllMessages();
Sherry Huangce02ed32019-01-17 20:37:29 +0800106 verify(mMockWarnings, never()).showHighTemperatureWarning();
107 verify(mMockWarnings, times(1)).dismissHighTemperatureWarning();
Jason Monkd819c312017-08-11 12:53:36 -0400108 }
109
110 @Test
Sherry Huangce02ed32019-01-17 20:37:29 +0800111 public void testSkinWarning_throttlingEmergency() throws Exception {
112 mPowerUI.start();
113
114 final Temperature temp = getEmergencyStatusTemp(Temperature.TYPE_SKIN, "skin2");
115 mThermalEventSkinListener.notifyThrottling(temp);
116
117 // show skin high temperature warning when throttling status is emergency
118 TestableLooper.get(this).processAllMessages();
119 verify(mMockWarnings, times(1)).showHighTemperatureWarning();
120 verify(mMockWarnings, never()).dismissHighTemperatureWarning();
121 }
122
123 @Test
124 public void testUsbAlarm_throttlingCritical() throws Exception {
125 mPowerUI.start();
126
127 final Temperature temp = getCriticalStatusTemp(Temperature.TYPE_USB_PORT, "usb1");
128 mThermalEventUsbListener.notifyThrottling(temp);
129
130 // not show usb high temperature alarm when throttling status is critical
131 TestableLooper.get(this).processAllMessages();
132 verify(mMockWarnings, never()).showUsbHighTemperatureAlarm();
133 }
134
135 @Test
136 public void testUsbAlarm_throttlingEmergency() throws Exception {
137 mPowerUI.start();
138
139 final Temperature temp = getEmergencyStatusTemp(Temperature.TYPE_USB_PORT, "usb2");
140 mThermalEventUsbListener.notifyThrottling(temp);
141
142 // show usb high temperature alarm when throttling status is emergency
143 TestableLooper.get(this).processAllMessages();
144 verify(mMockWarnings, times(1)).showUsbHighTemperatureAlarm();
145 }
146
147 @Test
148 public void testSettingOverrideConfig_enableSkinTemperatureWarning() throws Exception {
Jason Monkd819c312017-08-11 12:53:36 -0400149 Settings.Global.putInt(mContext.getContentResolver(), SHOW_TEMPERATURE_WARNING, 1);
150 TestableResources resources = mContext.getOrCreateTestableResources();
151 resources.addOverride(R.integer.config_showTemperatureWarning, 0);
Jason Monkd819c312017-08-11 12:53:36 -0400152
153 mPowerUI.start();
Sherry Huangce02ed32019-01-17 20:37:29 +0800154 mPowerUI.registerThermalEventListener();
155
Wei Wangfeb9de62018-11-26 14:35:17 -0800156 TestableLooper.get(this).processAllMessages();
Sherry Huangce02ed32019-01-17 20:37:29 +0800157 verify(mThermalServiceMock, times(1))
158 .registerThermalEventListenerWithType(anyObject(), eq(Temperature.TYPE_SKIN));
Jason Monkd819c312017-08-11 12:53:36 -0400159 }
160
161 @Test
Sherry Huangce02ed32019-01-17 20:37:29 +0800162 public void testSettingOverrideConfig_enableUsbTemperatureAlarm() throws Exception {
163 Settings.Global.putInt(mContext.getContentResolver(), SHOW_USB_TEMPERATURE_ALARM, 1);
Jason Monkd819c312017-08-11 12:53:36 -0400164 TestableResources resources = mContext.getOrCreateTestableResources();
Sherry Huangce02ed32019-01-17 20:37:29 +0800165 resources.addOverride(R.integer.config_showUsbPortAlarm, 0);
Jason Monkd819c312017-08-11 12:53:36 -0400166
Jason Monkd819c312017-08-11 12:53:36 -0400167 mPowerUI.start();
Sherry Huangce02ed32019-01-17 20:37:29 +0800168 mPowerUI.registerThermalEventListener();
Jason Monkd819c312017-08-11 12:53:36 -0400169
Sherry Huangce02ed32019-01-17 20:37:29 +0800170 TestableLooper.get(this).processAllMessages();
171 verify(mThermalServiceMock, times(1))
172 .registerThermalEventListenerWithType(anyObject(), eq(Temperature.TYPE_USB_PORT));
Jason Monkd819c312017-08-11 12:53:36 -0400173 }
174
Salvador Martinezf9e47502018-01-04 13:45:48 -0800175 @Test
Salvador Martinez4387bd52019-02-21 16:16:28 -0800176 public void testMaybeShowHybridWarning() {
Salvador Martinezbb902fc2018-01-22 19:46:55 -0800177 mPowerUI.start();
178
Salvador Martinez4387bd52019-02-21 16:16:28 -0800179 // verify low warning shown this cycle noticed
180 BatteryStateSnapshotWrapper state = new BatteryStateSnapshotWrapper();
181 BatteryStateSnapshot lastState = state.get();
182 state.mTimeRemainingMillis = Duration.ofHours(2).toMillis();
183 state.mBatteryLevel = 15;
184
185 mPowerUI.maybeShowHybridWarning(state.get(), lastState);
186
187 assertThat(mPowerUI.mLowWarningShownThisChargeCycle).isTrue();
188 assertThat(mPowerUI.mSevereWarningShownThisChargeCycle).isFalse();
189
190 // verify severe warning noticed this cycle
191 lastState = state.get();
192 state.mBatteryLevel = 1;
193 state.mTimeRemainingMillis = Duration.ofMinutes(10).toMillis();
194
195 mPowerUI.maybeShowHybridWarning(state.get(), lastState);
196
197 assertThat(mPowerUI.mLowWarningShownThisChargeCycle).isTrue();
198 assertThat(mPowerUI.mSevereWarningShownThisChargeCycle).isTrue();
199
200 // verify getting past threshold resets values
201 lastState = state.get();
202 state.mBatteryLevel = 100;
203 state.mTimeRemainingMillis = Duration.ofDays(1).toMillis();
204
205 mPowerUI.maybeShowHybridWarning(state.get(), lastState);
206
207 assertThat(mPowerUI.mLowWarningShownThisChargeCycle).isFalse();
208 assertThat(mPowerUI.mSevereWarningShownThisChargeCycle).isFalse();
Salvador Martinezbb902fc2018-01-22 19:46:55 -0800209 }
210
211 @Test
Salvador Martinez4387bd52019-02-21 16:16:28 -0800212 public void testShouldShowHybridWarning_lowLevelWarning() {
Salvador Martinezbb902fc2018-01-22 19:46:55 -0800213 mPowerUI.start();
Salvador Martinez4387bd52019-02-21 16:16:28 -0800214 mPowerUI.mLowWarningShownThisChargeCycle = false;
215 mPowerUI.mSevereWarningShownThisChargeCycle = false;
216 BatteryStateSnapshotWrapper state = new BatteryStateSnapshotWrapper();
Salvador Martinezbb902fc2018-01-22 19:46:55 -0800217
Salvador Martinez4387bd52019-02-21 16:16:28 -0800218 // sanity check to make sure we can show for a valid config
219 state.mBatteryLevel = 10;
220 state.mTimeRemainingMillis = Duration.ofHours(2).toMillis();
221 boolean shouldShow = mPowerUI.shouldShowHybridWarning(state.get());
222 assertThat(shouldShow).isTrue();
223
224 // Shouldn't show if plugged in
225 state.mPlugged = true;
226 shouldShow = mPowerUI.shouldShowHybridWarning(state.get());
227 assertThat(shouldShow).isFalse();
228
229 // Shouldn't show if battery is unknown
230 state.mPlugged = false;
231 state.mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN;
232 shouldShow = mPowerUI.shouldShowHybridWarning(state.get());
233 assertThat(shouldShow).isFalse();
234
235 state.mBatteryStatus = BatteryManager.BATTERY_HEALTH_GOOD;
236 // Already shown both warnings
237 mPowerUI.mLowWarningShownThisChargeCycle = true;
238 mPowerUI.mSevereWarningShownThisChargeCycle = true;
239 shouldShow = mPowerUI.shouldShowHybridWarning(state.get());
240 assertThat(shouldShow).isFalse();
241
242 // Can show low warning
243 mPowerUI.mLowWarningShownThisChargeCycle = false;
244 shouldShow = mPowerUI.shouldShowHybridWarning(state.get());
245 assertThat(shouldShow).isTrue();
246
247 // Can't show if above the threshold for time & battery
248 state.mTimeRemainingMillis = Duration.ofHours(1000).toMillis();
249 state.mBatteryLevel = 100;
250 shouldShow = mPowerUI.shouldShowHybridWarning(state.get());
251 assertThat(shouldShow).isFalse();
252
253 // Battery under low percentage threshold but not time
254 state.mBatteryLevel = 10;
255 state.mLowLevelThreshold = 50;
256 shouldShow = mPowerUI.shouldShowHybridWarning(state.get());
257 assertThat(shouldShow).isTrue();
258
259 // Should also trigger if both level and time remaining under low threshold
260 state.mTimeRemainingMillis = Duration.ofHours(2).toMillis();
261 shouldShow = mPowerUI.shouldShowHybridWarning(state.get());
262 assertThat(shouldShow).isTrue();
263
264 // battery saver should block the low level warning though
265 state.mIsPowerSaver = true;
266 shouldShow = mPowerUI.shouldShowHybridWarning(state.get());
267 assertThat(shouldShow).isFalse();
Salvador Martinezbb902fc2018-01-22 19:46:55 -0800268 }
269
270 @Test
Salvador Martinez4387bd52019-02-21 16:16:28 -0800271 public void testShouldShowHybridWarning_severeLevelWarning() {
Salvador Martinezf9e47502018-01-04 13:45:48 -0800272 mPowerUI.start();
Salvador Martinez4387bd52019-02-21 16:16:28 -0800273 mPowerUI.mLowWarningShownThisChargeCycle = false;
274 mPowerUI.mSevereWarningShownThisChargeCycle = false;
275 BatteryStateSnapshotWrapper state = new BatteryStateSnapshotWrapper();
Salvador Martinezf9e47502018-01-04 13:45:48 -0800276
Salvador Martinez4387bd52019-02-21 16:16:28 -0800277 // sanity check to make sure we can show for a valid config
278 state.mBatteryLevel = 1;
279 state.mTimeRemainingMillis = Duration.ofMinutes(1).toMillis();
280 boolean shouldShow = mPowerUI.shouldShowHybridWarning(state.get());
281 assertThat(shouldShow).isTrue();
282
283 // Shouldn't show if plugged in
284 state.mPlugged = true;
285 shouldShow = mPowerUI.shouldShowHybridWarning(state.get());
286 assertThat(shouldShow).isFalse();
287
288 // Shouldn't show if battery is unknown
289 state.mPlugged = false;
290 state.mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN;
291 shouldShow = mPowerUI.shouldShowHybridWarning(state.get());
292 assertThat(shouldShow).isFalse();
293
294 state.mBatteryStatus = BatteryManager.BATTERY_HEALTH_GOOD;
295 // Already shown both warnings
296 mPowerUI.mLowWarningShownThisChargeCycle = true;
297 mPowerUI.mSevereWarningShownThisChargeCycle = true;
298 shouldShow = mPowerUI.shouldShowHybridWarning(state.get());
299 assertThat(shouldShow).isFalse();
300
301 // Can show severe warning
302 mPowerUI.mSevereWarningShownThisChargeCycle = false;
303 shouldShow = mPowerUI.shouldShowHybridWarning(state.get());
304 assertThat(shouldShow).isTrue();
305
306 // Can't show if above the threshold for time & battery
307 state.mTimeRemainingMillis = Duration.ofHours(1000).toMillis();
308 state.mBatteryLevel = 100;
309 shouldShow = mPowerUI.shouldShowHybridWarning(state.get());
310 assertThat(shouldShow).isFalse();
311
312 // Battery under low percentage threshold but not time
313 state.mBatteryLevel = 1;
314 state.mSevereLevelThreshold = 5;
315 shouldShow = mPowerUI.shouldShowHybridWarning(state.get());
316 assertThat(shouldShow).isTrue();
317
318 // Should also trigger if both level and time remaining under low threshold
319 state.mTimeRemainingMillis = Duration.ofHours(2).toMillis();
320 shouldShow = mPowerUI.shouldShowHybridWarning(state.get());
321 assertThat(shouldShow).isTrue();
322
323 // battery saver should not block the severe level warning though
324 state.mIsPowerSaver = true;
325 shouldShow = mPowerUI.shouldShowHybridWarning(state.get());
326 assertThat(shouldShow).isTrue();
Salvador Martinezf9e47502018-01-04 13:45:48 -0800327 }
328
329 @Test
Salvador Martinez4387bd52019-02-21 16:16:28 -0800330 public void testShouldDismissHybridWarning() {
Salvador Martinezf9e47502018-01-04 13:45:48 -0800331 mPowerUI.start();
Salvador Martinez4387bd52019-02-21 16:16:28 -0800332 BatteryStateSnapshotWrapper state = new BatteryStateSnapshotWrapper();
Salvador Martinezf9e47502018-01-04 13:45:48 -0800333
Salvador Martinez4387bd52019-02-21 16:16:28 -0800334 // We should dismiss if the device is plugged in
335 state.mPlugged = true;
336 state.mTimeRemainingMillis = Duration.ofHours(1).toMillis();
337 state.mLowThresholdMillis = Duration.ofHours(2).toMillis();
338 boolean shouldDismiss = mPowerUI.shouldDismissHybridWarning(state.get());
339 assertThat(shouldDismiss).isTrue();
340
341 // If not plugged in and below the threshold we should not dismiss
342 state.mPlugged = false;
343 shouldDismiss = mPowerUI.shouldDismissHybridWarning(state.get());
344 assertThat(shouldDismiss).isFalse();
345
346 // If we go over the low warning threshold we should dismiss
347 state.mTimeRemainingMillis = Duration.ofHours(3).toMillis();
348 shouldDismiss = mPowerUI.shouldDismissHybridWarning(state.get());
349 assertThat(shouldDismiss).isTrue();
Salvador Martinezf9e47502018-01-04 13:45:48 -0800350 }
351
352 @Test
Salvador Martinez4387bd52019-02-21 16:16:28 -0800353 public void testRefreshEstimateIfNeeded_onlyQueriesEstimateOnBatteryLevelChangeOrNull() {
Salvador Martinez926f0712018-07-03 18:07:07 -0700354 mPowerUI.start();
355 Estimate estimate = new Estimate(BELOW_HYBRID_THRESHOLD, true);
356 when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true);
357 when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS);
358 when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS);
359 when(mEnhancedEstimates.getEstimate()).thenReturn(estimate);
Salvador Martinez4387bd52019-02-21 16:16:28 -0800360 mPowerUI.mBatteryLevel = 10;
Salvador Martinez926f0712018-07-03 18:07:07 -0700361
Salvador Martinez4387bd52019-02-21 16:16:28 -0800362 // we expect that the first time it will query since there is no last battery snapshot.
363 // However an invalid estimate (-1) is returned.
364 Estimate refreshedEstimate = mPowerUI.refreshEstimateIfNeeded();
365 assertThat(refreshedEstimate.getEstimateMillis()).isEqualTo(BELOW_HYBRID_THRESHOLD);
366 BatteryStateSnapshot snapshot = new BatteryStateSnapshot(
367 BATTERY_LEVEL_10, false, false, 0, BatteryManager.BATTERY_HEALTH_GOOD,
368 0, 0, -1, 0, 0, false);
369 mPowerUI.mLastBatteryStateSnapshot = snapshot;
370
371 // query again since the estimate was -1
372 estimate = new Estimate(BELOW_SEVERE_HYBRID_THRESHOLD, true);
373 when(mEnhancedEstimates.getEstimate()).thenReturn(estimate);
374 refreshedEstimate = mPowerUI.refreshEstimateIfNeeded();
375 assertThat(refreshedEstimate.getEstimateMillis()).isEqualTo(BELOW_SEVERE_HYBRID_THRESHOLD);
376 snapshot = new BatteryStateSnapshot(
377 BATTERY_LEVEL_10, false, false, 0, BatteryManager.BATTERY_HEALTH_GOOD, 0,
378 0, BELOW_SEVERE_HYBRID_THRESHOLD, 0, 0, false);
379 mPowerUI.mLastBatteryStateSnapshot = snapshot;
380
381 // Battery level hasn't changed, so we don't query again
382 estimate = new Estimate(BELOW_HYBRID_THRESHOLD, true);
383 when(mEnhancedEstimates.getEstimate()).thenReturn(estimate);
384 refreshedEstimate = mPowerUI.refreshEstimateIfNeeded();
385 assertThat(refreshedEstimate.getEstimateMillis()).isEqualTo(BELOW_SEVERE_HYBRID_THRESHOLD);
386
387 // Battery level changes so we update again
Salvador Martinez926f0712018-07-03 18:07:07 -0700388 mPowerUI.mBatteryLevel = 9;
Salvador Martinez4387bd52019-02-21 16:16:28 -0800389 refreshedEstimate = mPowerUI.refreshEstimateIfNeeded();
390 assertThat(refreshedEstimate.getEstimateMillis()).isEqualTo(BELOW_HYBRID_THRESHOLD);
391 }
Salvador Martinez926f0712018-07-03 18:07:07 -0700392
Salvador Martinez4387bd52019-02-21 16:16:28 -0800393 @Test
394 public void testShouldShowStandardWarning() {
395 mPowerUI.start();
396 BatteryStateSnapshotWrapper state = new BatteryStateSnapshotWrapper();
397 state.mIsHybrid = false;
398 BatteryStateSnapshot lastState = state.get();
Salvador Martinez926f0712018-07-03 18:07:07 -0700399
Salvador Martinez4387bd52019-02-21 16:16:28 -0800400 // sanity check to make sure we can show for a valid config
401 state.mBatteryLevel = 10;
402 state.mBucket = -1;
403 boolean shouldShow = mPowerUI.shouldShowLowBatteryWarning(state.get(), lastState);
404 assertThat(shouldShow).isTrue();
405 lastState = state.get();
406
407 // Shouldn't show if plugged in
408 state.mPlugged = true;
409 shouldShow = mPowerUI.shouldShowLowBatteryWarning(state.get(), lastState);
410 assertThat(shouldShow).isFalse();
411
412 state.mPlugged = false;
413 // Shouldn't show if battery saver
414 state.mIsPowerSaver = true;
415 shouldShow = mPowerUI.shouldShowLowBatteryWarning(state.get(), lastState);
416 assertThat(shouldShow).isFalse();
417
418 state.mIsPowerSaver = false;
419 // Shouldn't show if battery is unknown
420 state.mPlugged = false;
421 state.mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN;
422 shouldShow = mPowerUI.shouldShowLowBatteryWarning(state.get(), lastState);
423 assertThat(shouldShow).isFalse();
424
425 state.mBatteryStatus = BatteryManager.BATTERY_HEALTH_GOOD;
426 // show if plugged -> unplugged, bucket -1 -> -1
427 state.mPlugged = true;
428 state.mBucket = -1;
429 lastState = state.get();
430 state.mPlugged = false;
431 state.mBucket = -1;
432 shouldShow = mPowerUI.shouldShowLowBatteryWarning(state.get(), lastState);
433 assertThat(shouldShow).isTrue();
434
435 // don't show if plugged -> unplugged, bucket 0 -> 0
436 state.mPlugged = true;
437 state.mBucket = 0;
438 lastState = state.get();
439 state.mPlugged = false;
440 state.mBucket = 0;
441 shouldShow = mPowerUI.shouldShowLowBatteryWarning(state.get(), lastState);
442 assertThat(shouldShow).isFalse();
443
444 // show if unplugged -> unplugged, bucket 0 -> -1
445 state.mPlugged = false;
446 state.mBucket = 0;
447 lastState = state.get();
448 state.mPlugged = false;
449 state.mBucket = -1;
450 shouldShow = mPowerUI.shouldShowLowBatteryWarning(state.get(), lastState);
451 assertThat(shouldShow).isTrue();
452
453 // don't show if unplugged -> unplugged, bucket -1 -> 1
454 state.mPlugged = false;
455 state.mBucket = -1;
456 lastState = state.get();
457 state.mPlugged = false;
458 state.mBucket = 1;
459 shouldShow = mPowerUI.shouldShowLowBatteryWarning(state.get(), lastState);
460 assertThat(shouldShow).isFalse();
461 }
462
463 @Test
464 public void testShouldDismissStandardWarning() {
465 mPowerUI.start();
466 BatteryStateSnapshotWrapper state = new BatteryStateSnapshotWrapper();
467 state.mIsHybrid = false;
468 BatteryStateSnapshot lastState = state.get();
469
470 // should dismiss if battery saver
471 state.mIsPowerSaver = true;
472 boolean shouldDismiss = mPowerUI.shouldDismissLowBatteryWarning(state.get(), lastState);
473 assertThat(shouldDismiss).isTrue();
474
475 state.mIsPowerSaver = false;
476 // should dismiss if plugged
477 state.mPlugged = true;
478 shouldDismiss = mPowerUI.shouldDismissLowBatteryWarning(state.get(), lastState);
479 assertThat(shouldDismiss).isTrue();
480
481 state.mPlugged = false;
482 // should dismiss if bucket 0 -> 1
483 state.mBucket = 0;
484 lastState = state.get();
485 state.mBucket = 1;
486 shouldDismiss = mPowerUI.shouldDismissLowBatteryWarning(state.get(), lastState);
487 assertThat(shouldDismiss).isTrue();
488
489 // shouldn't dismiss if bucket -1 -> 0
490 state.mBucket = -1;
491 lastState = state.get();
492 state.mBucket = 0;
493 shouldDismiss = mPowerUI.shouldDismissLowBatteryWarning(state.get(), lastState);
494 assertThat(shouldDismiss).isFalse();
495
496 // should dismiss if powersaver & bucket 0 -> 1
497 state.mIsPowerSaver = true;
498 state.mBucket = 0;
499 lastState = state.get();
500 state.mBucket = 1;
501 shouldDismiss = mPowerUI.shouldDismissLowBatteryWarning(state.get(), lastState);
502 assertThat(shouldDismiss).isTrue();
Salvador Martinez926f0712018-07-03 18:07:07 -0700503 }
504
Sherry Huangce02ed32019-01-17 20:37:29 +0800505 private Temperature getEmergencyStatusTemp(int type, String name) {
506 final float value = 65;
507 return new Temperature(value, type, name, Temperature.THROTTLING_EMERGENCY);
Jason Monkd819c312017-08-11 12:53:36 -0400508 }
509
Sherry Huangce02ed32019-01-17 20:37:29 +0800510 private Temperature getCriticalStatusTemp(int type, String name) {
511 final float value = 60;
512 return new Temperature(value, type, name, Temperature.THROTTLING_CRITICAL);
Jason Monkd819c312017-08-11 12:53:36 -0400513 }
514
515 private void createPowerUi() {
516 mPowerUI = new PowerUI();
517 mPowerUI.mContext = mContext;
518 mPowerUI.mComponents = mContext.getComponents();
Wei Wangbf05e602018-11-21 11:46:48 -0800519 mPowerUI.mThermalService = mThermalServiceMock;
Jason Monkd819c312017-08-11 12:53:36 -0400520 }
Salvador Martinez4387bd52019-02-21 16:16:28 -0800521
522 /**
523 * A simple wrapper class that sets values by default and makes them not final to improve
524 * test clarity.
525 */
526 private class BatteryStateSnapshotWrapper {
527 public int mBatteryLevel = 100;
528 public boolean mIsPowerSaver = false;
529 public boolean mPlugged = false;
530 public long mSevereThresholdMillis = Duration.ofHours(1).toMillis();
531 public long mLowThresholdMillis = Duration.ofHours(3).toMillis();
532 public int mSevereLevelThreshold = 5;
533 public int mLowLevelThreshold = 15;
534 public int mBucket = 1;
535 public int mBatteryStatus = BatteryManager.BATTERY_HEALTH_GOOD;
536 public long mTimeRemainingMillis = Duration.ofHours(24).toMillis();
537 public boolean mIsBasedOnUsage = true;
538 public boolean mIsHybrid = true;
539
540 public BatteryStateSnapshot get() {
541 if (mIsHybrid) {
542 return new BatteryStateSnapshot(mBatteryLevel, mIsPowerSaver, mPlugged, mBucket,
543 mBatteryStatus, mSevereLevelThreshold, mLowLevelThreshold,
544 mTimeRemainingMillis, mSevereThresholdMillis, mLowThresholdMillis,
545 mIsBasedOnUsage);
546 } else {
547 return new BatteryStateSnapshot(mBatteryLevel, mIsPowerSaver, mPlugged, mBucket,
548 mBatteryStatus, mSevereLevelThreshold, mLowLevelThreshold);
549 }
550 }
551 }
Jason Monkd819c312017-08-11 12:53:36 -0400552}