Home | History | Annotate | Download | only in batterysaver
      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