blob: e8394fe11d2e1de71ddc012020f93ef5d1db449d [file] [log] [blame]
Makoto Onukia3cd7b92018-03-19 14:47:05 -07001/*
2 * Copyright (C) 2018 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 */
16package com.android.server.power.batterysaver;
17
18import static org.junit.Assert.assertEquals;
19import static org.mockito.ArgumentMatchers.anyBoolean;
Makoto Onuki0f8617a2018-04-30 10:26:21 -070020import static org.mockito.ArgumentMatchers.anyInt;
Makoto Onukia3cd7b92018-03-19 14:47:05 -070021import static org.mockito.Mockito.doAnswer;
22import static org.mockito.Mockito.mock;
23import static org.mockito.Mockito.when;
24
25import android.content.ContentResolver;
26import android.provider.Settings.Global;
Makoto Onukia3cd7b92018-03-19 14:47:05 -070027import android.test.mock.MockContext;
28
Brett Chabot8091d9e2019-02-26 14:52:33 -080029import androidx.test.filters.SmallTest;
30import androidx.test.runner.AndroidJUnit4;
31
Makoto Onukia3cd7b92018-03-19 14:47:05 -070032import com.google.common.base.Objects;
33
34import org.junit.Before;
35import org.junit.Test;
36import org.junit.runner.RunWith;
37
38import java.util.HashMap;
39
40/**
41 atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
42 */
43@SmallTest
44@RunWith(AndroidJUnit4.class)
45public class BatterySaverStateMachineTest {
46
47 private MyMockContext mMockContext;
48 private ContentResolver mMockContextResolver;
49 private BatterySaverController mMockBatterySaverController;
50 private Device mDevice;
51 private TestableBatterySaverStateMachine mTarget;
52
53 private class MyMockContext extends MockContext {
54 @Override
55 public ContentResolver getContentResolver() {
56 return mMockContextResolver;
57 }
58 }
59
60 private DevicePersistedState mPersistedState;
61
62 private class DevicePersistedState {
63 // Current battery level.
64 public int batteryLevel = 100;
65
66 // Whether battery level is currently low or not.
67 public boolean batteryLow = false;
68
69 // Whether the device is plugged in or not.
70 public boolean powered = false;
71
72 // Global settings.
73 public final HashMap<String, Integer> global = new HashMap<>();
74 }
75
76 /**
77 * This class simulates a device's volatile status that will be reset by {@link #initDevice()}.
78 */
79 private class Device {
80 public boolean batterySaverEnabled = false;
81
82 public int getLowPowerModeTriggerLevel() {
83 return mPersistedState.global.getOrDefault(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
84 }
85
86 public void setBatteryLevel(int level) {
87 mPersistedState.batteryLevel = level;
88 if (mPersistedState.batteryLevel <= Math.max(15, getLowPowerModeTriggerLevel())) {
89 mPersistedState.batteryLow = true;
90 } else if (mPersistedState.batteryLow
91 && (mPersistedState.batteryLevel >= (getLowPowerModeTriggerLevel() + 5))) {
92 mPersistedState.batteryLow = false;
93 }
94 pushBatteryStatus();
95 }
96
97 public void setPowered(boolean newPowered) {
98 mPersistedState.powered = newPowered;
99 pushBatteryStatus();
100 }
101
102 public void pushBatteryStatus() {
103 mTarget.setBatteryStatus(mPersistedState.powered, mPersistedState.batteryLevel,
104 mPersistedState.batteryLow);
105 }
106
107 public void pushGlobalSettings() {
108 mTarget.setSettingsLocked(
109 mPersistedState.global.getOrDefault(Global.LOW_POWER_MODE, 0) != 0,
110 mPersistedState.global.getOrDefault(Global.LOW_POWER_MODE_STICKY, 0) != 0,
111 mDevice.getLowPowerModeTriggerLevel());
112 }
113
114 public void putGlobalSetting(String key, int value) {
115 mPersistedState.global.put(key, value);
116 pushGlobalSettings();
117 }
118
119 public int getGlobalSetting(String key, int defValue) {
120 return mPersistedState.global.getOrDefault(key, defValue);
121 }
122 }
123
124 /**
125 * Test target class.
126 */
127 private class TestableBatterySaverStateMachine extends BatterySaverStateMachine {
128 public TestableBatterySaverStateMachine() {
Makoto Onukibd7a6252018-05-10 13:41:39 -0700129 super(new Object(), mMockContext, mMockBatterySaverController);
Makoto Onukia3cd7b92018-03-19 14:47:05 -0700130 }
131
132 @Override
133 protected void putGlobalSetting(String key, int value) {
134 if (Objects.equal(mPersistedState.global.get(key), value)) {
135 return;
136 }
137 mDevice.putGlobalSetting(key, value);
138 }
139
140 @Override
141 protected int getGlobalSetting(String key, int defValue) {
142 return mDevice.getGlobalSetting(key, defValue);
143 }
Makoto Onuki6e5eb1d2018-03-30 16:15:35 -0700144
145 @Override
146 void runOnBgThread(Runnable r) {
147 r.run();
148 }
Makoto Onuki0f8617a2018-04-30 10:26:21 -0700149
150 @Override
151 void runOnBgThreadLazy(Runnable r, int delayMillis) {
152 r.run();
153 }
Makoto Onukia3cd7b92018-03-19 14:47:05 -0700154 }
155
156 @Before
157 public void setUp() {
158 mMockContext = new MyMockContext();
159 mMockContextResolver = mock(ContentResolver.class);
160 mMockBatterySaverController = mock(BatterySaverController.class);
161
162 doAnswer((inv) -> mDevice.batterySaverEnabled = inv.getArgument(0))
Makoto Onuki0f8617a2018-04-30 10:26:21 -0700163 .when(mMockBatterySaverController).enableBatterySaver(anyBoolean(), anyInt());
Makoto Onukia3cd7b92018-03-19 14:47:05 -0700164 when(mMockBatterySaverController.isEnabled())
165 .thenAnswer((inv) -> mDevice.batterySaverEnabled);
166
167 mPersistedState = new DevicePersistedState();
168 initDevice();
169 }
170
171 private void initDevice() {
172 mDevice = new Device();
173
174 mTarget = new TestableBatterySaverStateMachine();
175
176 mDevice.pushBatteryStatus();
177 mDevice.pushGlobalSettings();
178 mTarget.onBootCompleted();
179 }
180
181 @Test
182 public void testNoAutoBatterySaver() {
183 assertEquals(0, mDevice.getLowPowerModeTriggerLevel());
184
185 assertEquals(false, mDevice.batterySaverEnabled);
186 assertEquals(100, mPersistedState.batteryLevel);
187 assertEquals(false, mPersistedState.batteryLow);
188
189 mDevice.setBatteryLevel(90);
190
191 assertEquals(false, mDevice.batterySaverEnabled);
192 assertEquals(90, mPersistedState.batteryLevel);
193 assertEquals(false, mPersistedState.batteryLow);
194
195 mDevice.setBatteryLevel(50);
196
197 assertEquals(false, mDevice.batterySaverEnabled);
198 assertEquals(50, mPersistedState.batteryLevel);
199 assertEquals(false, mPersistedState.batteryLow);
200
201 mDevice.setBatteryLevel(16);
202
203 assertEquals(false, mDevice.batterySaverEnabled);
204 assertEquals(16, mPersistedState.batteryLevel);
205 assertEquals(false, mPersistedState.batteryLow);
206
207 // When LOW_POWER_MODE_TRIGGER_LEVEL is 0, 15% will still trigger low-battery, but
208 // BS wont be enabled.
209 mDevice.setBatteryLevel(15);
210
211 assertEquals(false, mDevice.batterySaverEnabled);
212 assertEquals(15, mPersistedState.batteryLevel);
213 assertEquals(true, mPersistedState.batteryLow);
214
215 mDevice.setBatteryLevel(10);
216
217 assertEquals(false, mDevice.batterySaverEnabled);
218 assertEquals(10, mPersistedState.batteryLevel);
219 assertEquals(true, mPersistedState.batteryLow);
220
221 // Manually enable BS.
222 mTarget.setBatterySaverEnabledManually(true);
223
224 assertEquals(true, mDevice.batterySaverEnabled);
225 assertEquals(10, mPersistedState.batteryLevel);
226 assertEquals(true, mPersistedState.batteryLow);
227
228 mDevice.setBatteryLevel(50);
229
230 assertEquals(true, mDevice.batterySaverEnabled);
231 assertEquals(50, mPersistedState.batteryLevel);
232 assertEquals(false, mPersistedState.batteryLow);
233
234 // Start charging. It'll disable BS.
235 mDevice.setPowered(true);
236
237 assertEquals(false, mDevice.batterySaverEnabled);
238 assertEquals(50, mPersistedState.batteryLevel);
239 assertEquals(false, mPersistedState.batteryLow);
240
241 mDevice.setBatteryLevel(60);
242
243 assertEquals(false, mDevice.batterySaverEnabled);
244 assertEquals(60, mPersistedState.batteryLevel);
245 assertEquals(false, mPersistedState.batteryLow);
246
247 // Unplug.
248 mDevice.setPowered(false);
249
250 assertEquals(true, mDevice.batterySaverEnabled);
251 assertEquals(60, mPersistedState.batteryLevel);
252 assertEquals(false, mPersistedState.batteryLow);
253
254 mDevice.setBatteryLevel(10);
255
256 assertEquals(true, mDevice.batterySaverEnabled);
257 assertEquals(10, mPersistedState.batteryLevel);
258 assertEquals(true, mPersistedState.batteryLow);
259
260 mDevice.setBatteryLevel(80);
261
262 assertEquals(true, mDevice.batterySaverEnabled);
263 assertEquals(80, mPersistedState.batteryLevel);
264 assertEquals(false, mPersistedState.batteryLow);
265
266 // Reboot the device.
267 initDevice();
268
269 assertEquals(true, mDevice.batterySaverEnabled); // Sticky.
270 assertEquals(80, mPersistedState.batteryLevel);
271 assertEquals(false, mPersistedState.batteryLow);
272
273 mDevice.setBatteryLevel(30);
274 initDevice();
275
276 assertEquals(true, mDevice.batterySaverEnabled); // Still sticky.
277 assertEquals(30, mPersistedState.batteryLevel);
278 assertEquals(false, mPersistedState.batteryLow);
279
280 mTarget.setBatterySaverEnabledManually(false);
281
282 assertEquals(false, mDevice.batterySaverEnabled);
283 assertEquals(30, mPersistedState.batteryLevel);
284 assertEquals(false, mPersistedState.batteryLow);
285
286 initDevice(); // reboot.
287
288 assertEquals(false, mDevice.batterySaverEnabled);
289 assertEquals(30, mPersistedState.batteryLevel);
290 assertEquals(false, mPersistedState.batteryLow);
291 }
292
293 @Test
294 public void testAutoBatterySaver() {
295 mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
296
297 assertEquals(false, mDevice.batterySaverEnabled);
298 assertEquals(100, mPersistedState.batteryLevel);
299 assertEquals(false, mPersistedState.batteryLow);
300
301 mDevice.setBatteryLevel(90);
302
303 assertEquals(false, mDevice.batterySaverEnabled);
304 assertEquals(90, mPersistedState.batteryLevel);
305 assertEquals(false, mPersistedState.batteryLow);
306
307 mDevice.setBatteryLevel(51);
308
309 assertEquals(false, mDevice.batterySaverEnabled);
310 assertEquals(51, mPersistedState.batteryLevel);
311 assertEquals(false, mPersistedState.batteryLow);
312
313 // Hit the threshold. BS should be enabled.
314 mDevice.setBatteryLevel(50);
315
316 assertEquals(true, mDevice.batterySaverEnabled);
317 assertEquals(50, mPersistedState.batteryLevel);
318 assertEquals(true, mPersistedState.batteryLow);
319
320 // Battery goes up, but until it hits 55%, we still keep BS on.
321 mDevice.setBatteryLevel(54);
322
323 assertEquals(true, mDevice.batterySaverEnabled);
324 assertEquals(54, mPersistedState.batteryLevel);
325 assertEquals(true, mPersistedState.batteryLow);
326
327 // 50% + 5%, now BS will be off.
328 mDevice.setBatteryLevel(55);
329
330 assertEquals(false, mDevice.batterySaverEnabled);
331 assertEquals(55, mPersistedState.batteryLevel);
332 assertEquals(false, mPersistedState.batteryLow);
333
334 mDevice.setBatteryLevel(40);
335
336 assertEquals(true, mDevice.batterySaverEnabled);
337 assertEquals(40, mPersistedState.batteryLevel);
338 assertEquals(true, mPersistedState.batteryLow);
339
340 mDevice.setPowered(true);
341
342 assertEquals(false, mDevice.batterySaverEnabled);
343 assertEquals(40, mPersistedState.batteryLevel);
344 assertEquals(true, mPersistedState.batteryLow);
345
346 mDevice.setPowered(false);
347
348 assertEquals(true, mDevice.batterySaverEnabled);
349 assertEquals(40, mPersistedState.batteryLevel);
350 assertEquals(true, mPersistedState.batteryLow);
351
352 mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
353
354 assertEquals(false, mDevice.batterySaverEnabled);
355 assertEquals(40, mPersistedState.batteryLevel);
356 assertEquals(true, mPersistedState.batteryLow);
357
358 mDevice.setBatteryLevel(30);
359
360 assertEquals(false, mDevice.batterySaverEnabled);
361 assertEquals(30, mPersistedState.batteryLevel);
362 assertEquals(true, mPersistedState.batteryLow);
363
364 // Plug in and out, snooze will reset.
365 mDevice.setPowered(true);
366 mDevice.setPowered(false);
367
368 assertEquals(true, mDevice.batterySaverEnabled);
369 assertEquals(30, mPersistedState.batteryLevel);
370 assertEquals(true, mPersistedState.batteryLow);
371
372 mDevice.setPowered(true);
373 mDevice.setBatteryLevel(60);
374
375 assertEquals(false, mDevice.batterySaverEnabled);
376 assertEquals(60, mPersistedState.batteryLevel);
377 assertEquals(false, mPersistedState.batteryLow);
378
379 mDevice.setPowered(false);
380
381 assertEquals(false, mDevice.batterySaverEnabled);
382 assertEquals(60, mPersistedState.batteryLevel);
383 assertEquals(false, mPersistedState.batteryLow);
384
385 mDevice.setBatteryLevel(50);
386
387 assertEquals(true, mDevice.batterySaverEnabled);
388 assertEquals(50, mPersistedState.batteryLevel);
389 assertEquals(true, mPersistedState.batteryLow);
390
391 mDevice.setBatteryLevel(70);
392
393 assertEquals(false, mDevice.batterySaverEnabled);
394 assertEquals(70, mPersistedState.batteryLevel);
395 assertEquals(false, mPersistedState.batteryLow);
396
397 // Bump ump the threshold.
398 mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 70);
399 mDevice.setBatteryLevel(mPersistedState.batteryLevel);
400
401 assertEquals(true, mDevice.batterySaverEnabled);
402 assertEquals(70, mPersistedState.batteryLevel);
403 assertEquals(true, mPersistedState.batteryLow);
404
405 // Then down.
406 mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 60);
407 mDevice.setBatteryLevel(mPersistedState.batteryLevel);
408
409 assertEquals(false, mDevice.batterySaverEnabled);
410 assertEquals(70, mPersistedState.batteryLevel);
411 assertEquals(false, mPersistedState.batteryLow);
412
413 // Reboot in low state -> automatically enable BS.
414 mDevice.setPowered(false);
415 mDevice.setBatteryLevel(30);
416 mTarget.setBatterySaverEnabledManually(false);
417
418 assertEquals(false, mDevice.batterySaverEnabled);
419 assertEquals(30, mPersistedState.batteryLevel);
420 assertEquals(true, mPersistedState.batteryLow);
421
422 initDevice();
423
424 assertEquals(true, mDevice.batterySaverEnabled);
425 assertEquals(30, mPersistedState.batteryLevel);
426 assertEquals(true, mPersistedState.batteryLow);
427 }
428
429 @Test
430 public void testAutoBatterySaver_withSticky() {
431 mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
432
433 mTarget.setBatterySaverEnabledManually(true);
434
435 assertEquals(true, mDevice.batterySaverEnabled);
436 assertEquals(100, mPersistedState.batteryLevel);
437 assertEquals(false, mPersistedState.batteryLow);
438
439 mDevice.setBatteryLevel(30);
440
441 assertEquals(true, mDevice.batterySaverEnabled);
442 assertEquals(30, mPersistedState.batteryLevel);
443 assertEquals(true, mPersistedState.batteryLow);
444
445 mDevice.setBatteryLevel(80);
446
447 assertEquals(true, mDevice.batterySaverEnabled); // Still enabled.
448 assertEquals(80, mPersistedState.batteryLevel);
449 assertEquals(false, mPersistedState.batteryLow);
450
451 mDevice.setPowered(true);
452
453 assertEquals(false, mDevice.batterySaverEnabled);
454 assertEquals(80, mPersistedState.batteryLevel);
455 assertEquals(false, mPersistedState.batteryLow);
456
457 mDevice.setBatteryLevel(30);
458
459 assertEquals(false, mDevice.batterySaverEnabled);
460 assertEquals(30, mPersistedState.batteryLevel);
461 assertEquals(true, mPersistedState.batteryLow);
462
463 mDevice.setPowered(false);
464
465 assertEquals(true, mDevice.batterySaverEnabled); // Restores BS.
466 assertEquals(30, mPersistedState.batteryLevel);
467 assertEquals(true, mPersistedState.batteryLow);
468
469 mDevice.setPowered(true);
470 mDevice.setBatteryLevel(90);
471
472 assertEquals(false, mDevice.batterySaverEnabled);
473 assertEquals(90, mPersistedState.batteryLevel);
474 assertEquals(false, mPersistedState.batteryLow);
475
476 initDevice();
477
478 assertEquals(false, mDevice.batterySaverEnabled);
479 assertEquals(90, mPersistedState.batteryLevel);
480 assertEquals(false, mPersistedState.batteryLow);
481
482 mDevice.setPowered(false);
483
484 assertEquals(true, mDevice.batterySaverEnabled);
485 assertEquals(90, mPersistedState.batteryLevel);
486 assertEquals(false, mPersistedState.batteryLow);
487
488 mTarget.setBatterySaverEnabledManually(false);
489
490 assertEquals(false, mDevice.batterySaverEnabled);
491 assertEquals(90, mPersistedState.batteryLevel);
492 assertEquals(false, mPersistedState.batteryLow);
493
494 initDevice();
495
496 assertEquals(false, mDevice.batterySaverEnabled);
497 assertEquals(90, mPersistedState.batteryLevel);
498 assertEquals(false, mPersistedState.batteryLow);
499 }
500
501 @Test
502 public void testNoAutoBatterySaver_fromAdb() {
503
504 assertEquals(0, mDevice.getLowPowerModeTriggerLevel());
505
506 assertEquals(false, mDevice.batterySaverEnabled);
507 assertEquals(100, mPersistedState.batteryLevel);
508 assertEquals(false, mPersistedState.batteryLow);
509
510 mDevice.setBatteryLevel(90);
511
512 assertEquals(false, mDevice.batterySaverEnabled);
513 assertEquals(90, mPersistedState.batteryLevel);
514 assertEquals(false, mPersistedState.batteryLow);
515
516 // Enable
517 mDevice.putGlobalSetting(Global.LOW_POWER_MODE, 1);
518
519 assertEquals(true, mDevice.batterySaverEnabled);
520 assertEquals(90, mPersistedState.batteryLevel);
521 assertEquals(false, mPersistedState.batteryLow);
522
523 // Disable
524 mDevice.putGlobalSetting(Global.LOW_POWER_MODE, 0);
525
526 assertEquals(false, mDevice.batterySaverEnabled);
527 assertEquals(90, mPersistedState.batteryLevel);
528 assertEquals(false, mPersistedState.batteryLow);
529
530 // Enable again
531 mDevice.putGlobalSetting(Global.LOW_POWER_MODE, 1);
532
533 assertEquals(true, mDevice.batterySaverEnabled);
534 assertEquals(90, mPersistedState.batteryLevel);
535 assertEquals(false, mPersistedState.batteryLow);
536
537 // Reboot -- setting BS from adb is also sticky.
538 initDevice();
539
540 assertEquals(true, mDevice.batterySaverEnabled);
541 assertEquals(90, mPersistedState.batteryLevel);
542 assertEquals(false, mPersistedState.batteryLow);
543 }
544}