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